mirror of
https://github.com/weaveworks/scope.git
synced 2026-02-14 18:09:59 +00:00
@@ -31,6 +31,7 @@ func init() {
|
||||
|
||||
// ProbeConfig contains all the info needed for a probe to do HTTP requests
|
||||
type ProbeConfig struct {
|
||||
BasicAuth bool
|
||||
Token string
|
||||
ProbeVersion string
|
||||
ProbeID string
|
||||
@@ -38,7 +39,11 @@ type ProbeConfig struct {
|
||||
}
|
||||
|
||||
func (pc ProbeConfig) authorizeHeaders(headers http.Header) {
|
||||
headers.Set("Authorization", fmt.Sprintf("Scope-Probe token=%s", pc.Token))
|
||||
if pc.BasicAuth {
|
||||
headers.Set("Authorization", fmt.Sprintf("Basic %s", pc.Token))
|
||||
} else {
|
||||
headers.Set("Authorization", fmt.Sprintf("Scope-Probe token=%s", pc.Token))
|
||||
}
|
||||
headers.Set(xfer.ScopeProbeIDHeader, pc.ProbeID)
|
||||
headers.Set(xfer.ScopeProbeVersionHeader, pc.ProbeVersion)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goji/httpauth"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -300,6 +301,13 @@ func appMain(flags appFlags) {
|
||||
}.Wrap(handler)
|
||||
}
|
||||
|
||||
if flags.basicAuth {
|
||||
log.Infof("Basic authentication enabled")
|
||||
handler = httpauth.SimpleBasicAuth(flags.username, flags.password)(handler)
|
||||
} else {
|
||||
log.Infof("Basic authentication disabled")
|
||||
}
|
||||
|
||||
server := &graceful.Server{
|
||||
// we want to manage the stop condition ourselves below
|
||||
NoSignalHandling: true,
|
||||
|
||||
33
prog/main.go
33
prog/main.go
@@ -94,6 +94,9 @@ type flags struct {
|
||||
|
||||
type probeFlags struct {
|
||||
printOnStdout bool
|
||||
basicAuth bool
|
||||
username string
|
||||
password string
|
||||
token string
|
||||
httpListen string
|
||||
publishInterval time.Duration
|
||||
@@ -149,6 +152,10 @@ type appFlags struct {
|
||||
logHTTP bool
|
||||
logHTTPHeaders bool
|
||||
|
||||
basicAuth bool
|
||||
username string
|
||||
password string
|
||||
|
||||
weaveEnabled bool
|
||||
weaveAddr string
|
||||
weaveHostname string
|
||||
@@ -282,6 +289,9 @@ func setupFlags(flags *flags) {
|
||||
|
||||
// Probe flags
|
||||
flag.BoolVar(&flags.probe.printOnStdout, "probe.publish.stdout", false, "Print reports on stdout instead of sending to app, for debugging")
|
||||
flag.BoolVar(&flags.probe.basicAuth, "probe.basicAuth", false, "Use basic authentication to authenticate with app")
|
||||
flag.StringVar(&flags.probe.username, "probe.basicAuth.username", "admin", "Username for basic authentication")
|
||||
flag.StringVar(&flags.probe.password, "probe.basicAuth.password", "admin", "Password for basic authentication")
|
||||
flag.StringVar(&flags.probe.token, serviceTokenFlag, "", "Token to authenticate with cloud.weave.works")
|
||||
flag.StringVar(&flags.probe.token, probeTokenFlag, "", "Token to authenticate with cloud.weave.works")
|
||||
flag.StringVar(&flags.probe.httpListen, "probe.http.listen", "", "listen address for HTTP profiling and instrumentation server")
|
||||
@@ -353,6 +363,10 @@ func setupFlags(flags *flags) {
|
||||
flag.BoolVar(&flags.app.logHTTP, "app.log.http", false, "Log individual HTTP requests")
|
||||
flag.BoolVar(&flags.app.logHTTPHeaders, "app.log.httpHeaders", false, "Log HTTP headers. Needs app.log.http to be enabled.")
|
||||
|
||||
flag.BoolVar(&flags.app.basicAuth, "app.basicAuth", false, "Enable basic authentication for app")
|
||||
flag.StringVar(&flags.app.username, "app.basicAuth.username", "admin", "Username for basic authentication")
|
||||
flag.StringVar(&flags.app.password, "app.basicAuth.password", "admin", "Password for basic authentication")
|
||||
|
||||
flag.StringVar(&flags.app.weaveAddr, "app.weave.addr", app.DefaultWeaveURL, "Address on which to contact WeaveDNS")
|
||||
flag.StringVar(&flags.app.weaveHostname, "app.weave.hostname", "", "Hostname to advertise in WeaveDNS")
|
||||
flag.StringVar(&flags.app.containerName, "app.container.name", app.DefaultContainerName, "Name of this container (to lookup container ID)")
|
||||
@@ -449,6 +463,25 @@ func main() {
|
||||
flags.probe.kubernetesNodeName = os.Getenv("KUBERNETES_NODENAME")
|
||||
}
|
||||
|
||||
if strings.ToLower(os.Getenv("ENABLE_BASIC_AUTH")) == "true" {
|
||||
flags.probe.basicAuth = true
|
||||
flags.app.basicAuth = true
|
||||
} else if strings.ToLower(os.Getenv("ENABLE_BASIC_AUTH")) == "false" {
|
||||
flags.probe.basicAuth = false
|
||||
flags.app.basicAuth = false
|
||||
}
|
||||
|
||||
username := os.Getenv("BASIC_AUTH_USERNAME")
|
||||
if username != "" {
|
||||
flags.probe.username = username
|
||||
flags.app.username = username
|
||||
}
|
||||
password := os.Getenv("BASIC_AUTH_PASSWORD")
|
||||
if password != "" {
|
||||
flags.probe.password = password
|
||||
flags.app.password = password
|
||||
}
|
||||
|
||||
if flags.dryRun {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -97,6 +99,12 @@ func probeMain(flags probeFlags, targets []appclient.Target) {
|
||||
setLogLevel(flags.logLevel)
|
||||
setLogFormatter(flags.logPrefix)
|
||||
|
||||
if flags.basicAuth {
|
||||
log.Infof("Basic authentication enabled")
|
||||
} else {
|
||||
log.Infof("Basic authentication disabled")
|
||||
}
|
||||
|
||||
traceCloser := tracing.NewFromEnv("scope-probe")
|
||||
defer traceCloser.Close()
|
||||
|
||||
@@ -143,7 +151,13 @@ func probeMain(flags probeFlags, targets []appclient.Target) {
|
||||
token = url.User.Username()
|
||||
url.User = nil // erase credentials, as we use a special header
|
||||
}
|
||||
|
||||
if flags.basicAuth {
|
||||
token = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", flags.username, flags.password)))
|
||||
}
|
||||
|
||||
probeConfig := appclient.ProbeConfig{
|
||||
BasicAuth: flags.basicAuth,
|
||||
Token: token,
|
||||
ProbeVersion: version,
|
||||
ProbeID: probeID,
|
||||
|
||||
20
vendor/github.com/goji/httpauth/LICENSE
generated
vendored
Normal file
20
vendor/github.com/goji/httpauth/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2014 Carl Jackson (carl@avtok.com), Matt Silverlock (matt@eatsleeprepeat.net)
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
185
vendor/github.com/goji/httpauth/basic_auth.go
generated
vendored
Normal file
185
vendor/github.com/goji/httpauth/basic_auth.go
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
package httpauth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type basicAuth struct {
|
||||
h http.Handler
|
||||
opts AuthOptions
|
||||
}
|
||||
|
||||
// AuthOptions stores the configuration for HTTP Basic Authentication.
|
||||
//
|
||||
// A http.Handler may also be passed to UnauthorizedHandler to override the
|
||||
// default error handler if you wish to serve a custom template/response.
|
||||
type AuthOptions struct {
|
||||
Realm string
|
||||
User string
|
||||
Password string
|
||||
AuthFunc func(string, string, *http.Request) bool
|
||||
UnauthorizedHandler http.Handler
|
||||
}
|
||||
|
||||
// Satisfies the http.Handler interface for basicAuth.
|
||||
func (b basicAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Check if we have a user-provided error handler, else set a default
|
||||
if b.opts.UnauthorizedHandler == nil {
|
||||
b.opts.UnauthorizedHandler = http.HandlerFunc(defaultUnauthorizedHandler)
|
||||
}
|
||||
|
||||
// Check that the provided details match
|
||||
if b.authenticate(r) == false {
|
||||
b.requestAuth(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the next handler on success.
|
||||
b.h.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// authenticate retrieves and then validates the user:password combination provided in
|
||||
// the request header. Returns 'false' if the user has not successfully authenticated.
|
||||
func (b *basicAuth) authenticate(r *http.Request) bool {
|
||||
const basicScheme string = "Basic "
|
||||
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// In simple mode, prevent authentication with empty credentials if User is
|
||||
// not set. Allow empty passwords to support non-password use-cases.
|
||||
if b.opts.AuthFunc == nil && b.opts.User == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Confirm the request is sending Basic Authentication credentials.
|
||||
auth := r.Header.Get("Authorization")
|
||||
if !strings.HasPrefix(auth, basicScheme) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get the plain-text username and password from the request.
|
||||
// The first six characters are skipped - e.g. "Basic ".
|
||||
str, err := base64.StdEncoding.DecodeString(auth[len(basicScheme):])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Split on the first ":" character only, with any subsequent colons assumed to be part
|
||||
// of the password. Note that the RFC2617 standard does not place any limitations on
|
||||
// allowable characters in the password.
|
||||
creds := bytes.SplitN(str, []byte(":"), 2)
|
||||
|
||||
if len(creds) != 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
givenUser := string(creds[0])
|
||||
givenPass := string(creds[1])
|
||||
|
||||
// Default to Simple mode if no AuthFunc is defined.
|
||||
if b.opts.AuthFunc == nil {
|
||||
b.opts.AuthFunc = b.simpleBasicAuthFunc
|
||||
}
|
||||
|
||||
return b.opts.AuthFunc(givenUser, givenPass, r)
|
||||
}
|
||||
|
||||
// simpleBasicAuthFunc authenticates the supplied username and password against
|
||||
// the User and Password set in the Options struct.
|
||||
func (b *basicAuth) simpleBasicAuthFunc(user, pass string, r *http.Request) bool {
|
||||
// Equalize lengths of supplied and required credentials
|
||||
// by hashing them
|
||||
givenUser := sha256.Sum256([]byte(user))
|
||||
givenPass := sha256.Sum256([]byte(pass))
|
||||
requiredUser := sha256.Sum256([]byte(b.opts.User))
|
||||
requiredPass := sha256.Sum256([]byte(b.opts.Password))
|
||||
|
||||
// Compare the supplied credentials to those set in our options
|
||||
if subtle.ConstantTimeCompare(givenUser[:], requiredUser[:]) == 1 &&
|
||||
subtle.ConstantTimeCompare(givenPass[:], requiredPass[:]) == 1 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Require authentication, and serve our error handler otherwise.
|
||||
func (b *basicAuth) requestAuth(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm=%q`, b.opts.Realm))
|
||||
b.opts.UnauthorizedHandler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// defaultUnauthorizedHandler provides a default HTTP 401 Unauthorized response.
|
||||
func defaultUnauthorizedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
// BasicAuth provides HTTP middleware for protecting URIs with HTTP Basic Authentication
|
||||
// as per RFC 2617. The server authenticates a user:password combination provided in the
|
||||
// "Authorization" HTTP header.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import(
|
||||
// "net/http"
|
||||
// "github.com/zenazn/goji"
|
||||
// "github.com/goji/httpauth"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// basicOpts := httpauth.AuthOptions{
|
||||
// Realm: "Restricted",
|
||||
// User: "Dave",
|
||||
// Password: "ClearText",
|
||||
// }
|
||||
//
|
||||
// goji.Use(httpauth.BasicAuth(basicOpts), SomeOtherMiddleware)
|
||||
// goji.Get("/thing", myHandler)
|
||||
// }
|
||||
//
|
||||
// Note: HTTP Basic Authentication credentials are sent in plain text, and therefore it does
|
||||
// not make for a wholly secure authentication mechanism. You should serve your content over
|
||||
// HTTPS to mitigate this, noting that "Basic Authentication" is meant to be just that: basic!
|
||||
func BasicAuth(o AuthOptions) func(http.Handler) http.Handler {
|
||||
fn := func(h http.Handler) http.Handler {
|
||||
return basicAuth{h, o}
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// SimpleBasicAuth is a convenience wrapper around BasicAuth. It takes a user and password, and
|
||||
// returns a pre-configured BasicAuth handler using the "Restricted" realm and a default 401 handler.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import(
|
||||
// "net/http"
|
||||
// "github.com/zenazn/goji/web/httpauth"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
//
|
||||
// goji.Use(httpauth.SimpleBasicAuth("dave", "somepassword"), SomeOtherMiddleware)
|
||||
// goji.Get("/thing", myHandler)
|
||||
// }
|
||||
//
|
||||
func SimpleBasicAuth(user, password string) func(http.Handler) http.Handler {
|
||||
opts := AuthOptions{
|
||||
Realm: "Restricted",
|
||||
User: user,
|
||||
Password: password,
|
||||
}
|
||||
return BasicAuth(opts)
|
||||
}
|
||||
8
vendor/manifest
vendored
8
vendor/manifest
vendored
@@ -871,6 +871,14 @@
|
||||
"path": "types",
|
||||
"notests": true
|
||||
},
|
||||
{
|
||||
"importpath": "github.com/goji/httpauth",
|
||||
"repository": "https://github.com/goji/httpauth",
|
||||
"vcs": "git",
|
||||
"revision": "2da839ab0f4df05a6db5eb277995589dadbd4fb9",
|
||||
"branch": "master",
|
||||
"notests": true
|
||||
},
|
||||
{
|
||||
"importpath": "github.com/golang/glog",
|
||||
"repository": "https://github.com/golang/glog",
|
||||
|
||||
Reference in New Issue
Block a user