Skip to content

Commit

Permalink
Adds support for Grafana API key Auth (#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
ronansalmon authored Mar 8, 2023
1 parent 3a24b5b commit 353ed9b
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 4 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ NOTE: Flags with parameters should use an "equals" (-autofit=true, -URL=https://
```TEXT
-URL string
URL to Grafana server (default "https://play.grafana.org")
-apikey string
apikey
-audience string
idtoken audience
-auto-login
Expand All @@ -78,7 +80,7 @@ NOTE: Flags with parameters should use an "equals" (-autofit=true, -URL=https://
disabled = omit option
(default "full")
-login-method string
[anon|local|gcom|goauth|idtoken] (default "anon")
[anon|local|gcom|goauth|idtoken|apikey] (default "anon")
-lxde
Initialize LXDE for kiosk mode
-lxde-home string
Expand Down Expand Up @@ -137,7 +139,7 @@ They can also be used instead of a configuration file.
KIOSK_IS_PLAYLIST bool
URL is a playlist (default "false")
KIOSK_LOGIN_METHOD string
[anon|local|gcom|goauth|idtoken] (default "anon")
[anon|local|gcom|goauth|idtoken|apikey] (default "anon")
KIOSK_LOGIN_PASSWORD string
password (default "guest")
KIOSK_URL string
Expand All @@ -154,6 +156,8 @@ They can also be used instead of a configuration file.
JSON Credentials for idtoken
KIOSK_IDTOKEN_AUDIENCE string
Audience for idtoken, tpyically your oauth client id
KIOSK_APIKEY_APIKEY string
Grafana API keys
```

### Hosted Grafana using grafana.com authentication
Expand Down Expand Up @@ -204,6 +208,13 @@ This will take the browser to a playlist on play.grafana.org in fullscreen kiosk
./bin/grafana-kiosk -URL=https://play.grafana.org/playlists/play/1 -login-method=anon -kiosk-mode=tv
```

### Grafana Server with Api Key

This will take the browser to the default dashboard on play.grafana.org in fullscreen kiosk mode:
```bash
./bin/grafana-kiosk -URL=https://play.grafana.org -login-method apikey --apikey "xxxxxxxxxxxxxxx" -kiosk-mode=tv
```

### Grafana Server with Generic Oauth

This will login to a Generic Oauth service, configured on Grafana. Oauth_auto_login is disabeld. As Oauth provider is Keycloak used.
Expand Down
11 changes: 9 additions & 2 deletions pkg/cmd/grafana-kiosk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Args struct {
LXDEEnabled bool
Audience string
KeyFile string
Apikey string
LXDEHome string
ConfigPath string
Mode string
Expand All @@ -40,7 +41,7 @@ func ProcessArgs(cfg interface{}) Args {

flagSettings := flag.NewFlagSet("grafana-kiosk", flag.ContinueOnError)
flagSettings.StringVar(&processedArgs.ConfigPath, "c", "", "Path to configuration file (config.yaml)")
flagSettings.StringVar(&processedArgs.LoginMethod, "login-method", "anon", "[anon|local|gcom|goauth|idtoken]")
flagSettings.StringVar(&processedArgs.LoginMethod, "login-method", "anon", "[anon|local|gcom|goauth|idtoken|apikey]")
flagSettings.StringVar(&processedArgs.Username, "username", "guest", "username")
flagSettings.StringVar(&processedArgs.Password, "password", "guest", "password")
flagSettings.StringVar(&processedArgs.Mode, "kiosk-mode", "full", "Kiosk Display Mode [full|tv|disabled]\nfull = No TOPNAV and No SIDEBAR\ntv = No SIDEBAR\ndisabled = omit option\n")
Expand All @@ -56,6 +57,7 @@ func ProcessArgs(cfg interface{}) Args {
flagSettings.StringVar(&processedArgs.PasswordField, "field-password", "password", "Fieldname for the password")
flagSettings.StringVar(&processedArgs.Audience, "audience", "", "idtoken audience")
flagSettings.StringVar(&processedArgs.KeyFile, "keyfile", "key.json", "idtoken json credentials")
flagSettings.StringVar(&processedArgs.Apikey, "apikey", "", "apikey")

fu := flagSettings.Usage
flagSettings.Usage = func() {
Expand Down Expand Up @@ -130,7 +132,7 @@ func main() {

// validate auth methods
switch args.LoginMethod {
case "goauth", "anon", "local", "gcom", "idtoken":
case "goauth", "anon", "local", "gcom", "idtoken", "apikey":
default:
log.Println("Invalid auth method", args.LoginMethod)
os.Exit(-1)
Expand Down Expand Up @@ -170,6 +172,8 @@ func main() {

cfg.IDTOKEN.Audience = args.Audience
cfg.IDTOKEN.KeyFile = args.KeyFile

cfg.APIKEY.Apikey = args.Apikey
}

summary(&cfg)
Expand Down Expand Up @@ -206,6 +210,9 @@ func main() {
case "idtoken":
log.Printf("Launching idtoken oauth kiosk")
kiosk.GrafanaKioskIDToken(&cfg)
case "apikey":
log.Printf("Launching apikey kiosk")
kiosk.GrafanaKioskApikey(&cfg)
default:
log.Printf("Launching ANON login kiosk")
kiosk.GrafanaKioskAnonymous(&cfg)
Expand Down
67 changes: 67 additions & 0 deletions pkg/kiosk/apikey_login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package kiosk

import (
"context"
"log"
"os"
"time"


"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
)

// GrafanaKioskApikey creates a chrome-based kiosk using a grafana api key.
func GrafanaKioskApikey(cfg *Config) {
dir, err := os.MkdirTemp(os.TempDir(), "chromedp-kiosk")
if err != nil {
panic(err)
}

log.Println("Using temp dir:", dir)
defer os.RemoveAll(dir)

opts := generateExecutorOptions(dir, cfg.General.WindowPosition, cfg.Target.IgnoreCertificateErrors)

allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()

// also set up a custom logger
taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
defer cancel()

listenChromeEvents(taskCtx, consoleAPICall|targetCrashed)

// ensure that the browser process is started
if err := chromedp.Run(taskCtx); err != nil {
panic(err)
}

// Give browser time to load next page (this can be prone to failure, explore different options vs sleeping)
time.Sleep(2000 * time.Millisecond)

var generatedURL = GenerateURL(cfg.Target.URL, cfg.General.Mode, cfg.General.AutoFit, cfg.Target.IsPlayList)

log.Println("Navigating to ", generatedURL)
/*
Launch chrome and look for main-view element
*/
headers := map[string]interface{}{
"Authorization": "Bearer " + cfg.APIKEY.Apikey,
}
if err := chromedp.Run(taskCtx,
network.Enable(),
network.SetExtraHTTPHeaders(network.Headers(headers)),
chromedp.Navigate(generatedURL),
chromedp.WaitVisible(`//div[@class="main-view"]`, chromedp.BySearch),
// wait forever (for now)
chromedp.WaitVisible("notinputPassword", chromedp.ByID),
); err != nil {
panic(err)
}

log.Println("Sleep before exit...")
// wait here for the process to exit
time.Sleep(2000 * time.Millisecond)
log.Println("Exit...")
}
3 changes: 3 additions & 0 deletions pkg/kiosk/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ type Config struct {
KeyFile string `yaml:"idtoken-keyfile" env:"KIOSK_IDTOKEN_KEYFILE" env-default:"key.json" env-description:"JSON Credentials for idtoken"`
Audience string `yaml:"idtoken-audience" env:"KIOSK_IDTOKEN_AUDIENCE" env-description:"Audience for idtoken, tpyically your oauth client id"`
} `yaml:"idtoken"`
APIKEY struct {
Apikey string `yaml:"apikey" env:"KIOSK_APIKEY_APIKEY" env-description:"APIKEY"`
} `yaml:"apikey"`
}

0 comments on commit 353ed9b

Please sign in to comment.