Support multiple API keys (command-line and config) (fixes #2747)

This commit is contained in:
Antony Male 2016-01-29 17:16:01 +00:00
parent 8ff7531f89
commit 5971c00a4f
5 changed files with 18 additions and 10 deletions

View File

@ -238,7 +238,7 @@ func (s *apiService) Serve() {
// Wrap everything in CSRF protection. The /rest prefix should be
// protected, other requests will grant cookies.
handler := csrfMiddleware(s.id.String()[:5], "/rest", guiCfg.APIKey(), mux)
handler := csrfMiddleware(s.id.String()[:5], "/rest", guiCfg, mux)
// Add the CORS handling
handler = corsMiddleware(handler)

View File

@ -33,9 +33,8 @@ func emitLoginAttempt(success bool, username string) {
}
func basicAuthAndSessionMiddleware(cookieName string, cfg config.GUIConfiguration, next http.Handler) http.Handler {
apiKey := cfg.APIKey()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if apiKey != "" && r.Header.Get("X-API-Key") == apiKey {
if cfg.IsValidAPIKey(r.Header.Get("X-API-Key")) {
next.ServeHTTP(w, r)
return
}

View File

@ -13,6 +13,7 @@ import (
"os"
"strings"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/sync"
)
@ -30,11 +31,11 @@ const maxCsrfTokens = 25
// Check for CSRF token on /rest/ URLs. If a correct one is not given, reject
// the request with 403. For / and /index.html, set a new CSRF cookie if none
// is currently set.
func csrfMiddleware(unique, prefix, apiKey string, next http.Handler) http.Handler {
func csrfMiddleware(unique string, prefix string, cfg config.GUIConfiguration, next http.Handler) http.Handler {
loadCsrfTokens()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Allow requests carrying a valid API key
if apiKey != "" && r.Header.Get("X-API-Key") == apiKey {
if cfg.IsValidAPIKey(r.Header.Get("X-API-Key")) {
next.ServeHTTP(w, r)
return
}

View File

@ -478,7 +478,7 @@ func upgradeViaRest() error {
cfg, _ := loadConfig()
target := cfg.GUI().URL()
r, _ := http.NewRequest("POST", target+"/rest/system/upgrade", nil)
r.Header.Set("X-API-Key", cfg.GUI().APIKey())
r.Header.Set("X-API-Key", cfg.GUI().RawAPIKey)
tr := &http.Transport{
Dial: dialer.Dial,

View File

@ -76,9 +76,17 @@ func (c GUIConfiguration) URL() string {
return u.String()
}
func (c GUIConfiguration) APIKey() string {
if override := os.Getenv("STGUIAPIKEY"); override != "" {
return override
// Returns whether the given API key is valid, including both the value in config
// and any overrides
func (c GUIConfiguration) IsValidAPIKey(apiKey string) bool {
switch apiKey {
case "":
return false
case c.RawAPIKey, os.Getenv("STGUIAPIKEY"):
return true
default:
return false
}
return c.RawAPIKey
}