1
0
Fork 0

Opentracing support

This commit is contained in:
Michael 2018-01-10 17:48:04 +01:00 committed by Traefiker
parent 8394549857
commit 30ffba78e6
272 changed files with 44352 additions and 63 deletions

View file

@ -8,6 +8,7 @@ import (
goauth "github.com/abbot/go-http-auth"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/types"
"github.com/urfave/negroni"
)
@ -18,57 +19,85 @@ type Authenticator struct {
users map[string]string
}
type tracingAuthenticator struct {
name string
handler negroni.Handler
clientSpanKind bool
}
// NewAuthenticator builds a new Authenticator given a config
func NewAuthenticator(authConfig *types.Auth) (*Authenticator, error) {
func NewAuthenticator(authConfig *types.Auth, tracingMiddleware *tracing.Tracing) (*Authenticator, error) {
if authConfig == nil {
return nil, fmt.Errorf("Error creating Authenticator: auth is nil")
return nil, fmt.Errorf("error creating Authenticator: auth is nil")
}
var err error
authenticator := Authenticator{}
tracingAuthenticator := tracingAuthenticator{}
if authConfig.Basic != nil {
authenticator.users, err = parserBasicUsers(authConfig.Basic)
if err != nil {
return nil, err
}
basicAuth := goauth.NewBasicAuthenticator("traefik", authenticator.secretBasic)
authenticator.handler = negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if username := basicAuth.CheckAuth(r); username == "" {
log.Debug("Basic auth failed...")
basicAuth.RequireAuth(w, r)
} else {
log.Debug("Basic auth success...")
if authConfig.HeaderField != "" {
r.Header[authConfig.HeaderField] = []string{username}
}
next.ServeHTTP(w, r)
}
})
tracingAuthenticator.handler = createAuthBasicHandler(basicAuth, authConfig)
tracingAuthenticator.name = "Auth Basic"
tracingAuthenticator.clientSpanKind = false
} else if authConfig.Digest != nil {
authenticator.users, err = parserDigestUsers(authConfig.Digest)
if err != nil {
return nil, err
}
digestAuth := goauth.NewDigestAuthenticator("traefik", authenticator.secretDigest)
authenticator.handler = negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if username, _ := digestAuth.CheckAuth(r); username == "" {
log.Debug("Digest auth failed...")
digestAuth.RequireAuth(w, r)
} else {
log.Debug("Digest auth success...")
if authConfig.HeaderField != "" {
r.Header[authConfig.HeaderField] = []string{username}
}
next.ServeHTTP(w, r)
}
})
tracingAuthenticator.handler = createAuthDigestHandler(digestAuth, authConfig)
tracingAuthenticator.name = "Auth Digest"
tracingAuthenticator.clientSpanKind = false
} else if authConfig.Forward != nil {
authenticator.handler = negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
Forward(authConfig.Forward, w, r, next)
})
tracingAuthenticator.handler = createAuthForwardHandler(authConfig)
tracingAuthenticator.name = "Auth Forward"
tracingAuthenticator.clientSpanKind = true
}
if tracingMiddleware != nil {
authenticator.handler = tracingMiddleware.NewNegroniHandlerWrapper(tracingAuthenticator.name, tracingAuthenticator.handler, tracingAuthenticator.clientSpanKind)
} else {
authenticator.handler = tracingAuthenticator.handler
}
return &authenticator, nil
}
func createAuthForwardHandler(authConfig *types.Auth) negroni.HandlerFunc {
return negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
Forward(authConfig.Forward, w, r, next)
})
}
func createAuthDigestHandler(digestAuth *goauth.DigestAuth, authConfig *types.Auth) negroni.HandlerFunc {
return negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if username, _ := digestAuth.CheckAuth(r); username == "" {
log.Debugf("Digest auth failed")
digestAuth.RequireAuth(w, r)
} else {
log.Debugf("Digest auth succeeded")
if authConfig.HeaderField != "" {
r.Header[authConfig.HeaderField] = []string{username}
}
next.ServeHTTP(w, r)
}
})
}
func createAuthBasicHandler(basicAuth *goauth.BasicAuth, authConfig *types.Auth) negroni.HandlerFunc {
return negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if username := basicAuth.CheckAuth(r); username == "" {
log.Debugf("Basic auth failed")
basicAuth.RequireAuth(w, r)
} else {
if authConfig.HeaderField != "" {
r.Header[authConfig.HeaderField] = []string{username}
}
log.Debugf("Basic auth succeeded")
next.ServeHTTP(w, r)
}
})
}
func getLinesFromFile(filename string) ([]string, error) {
dat, err := ioutil.ReadFile(filename)
if err != nil {

View file

@ -8,6 +8,7 @@ import (
"os"
"testing"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/testhelpers"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
@ -70,14 +71,14 @@ func TestBasicAuthFail(t *testing.T) {
Basic: &types.Basic{
Users: []string{"test"},
},
})
}, &tracing.Tracing{})
assert.Contains(t, err.Error(), "Error parsing Authenticator user", "should contains")
authMiddleware, err := NewAuthenticator(&types.Auth{
Basic: &types.Basic{
Users: []string{"test:test"},
},
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -101,7 +102,7 @@ func TestBasicAuthSuccess(t *testing.T) {
Basic: &types.Basic{
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
},
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -129,14 +130,14 @@ func TestDigestAuthFail(t *testing.T) {
Digest: &types.Digest{
Users: []string{"test"},
},
})
}, &tracing.Tracing{})
assert.Contains(t, err.Error(), "Error parsing Authenticator user", "should contains")
authMiddleware, err := NewAuthenticator(&types.Auth{
Digest: &types.Digest{
Users: []string{"test:traefik:test"},
},
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
assert.NotNil(t, authMiddleware, "this should not be nil")
@ -162,7 +163,7 @@ func TestBasicAuthUserHeader(t *testing.T) {
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
},
HeaderField: "X-Webauth-User",
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View file

@ -7,6 +7,7 @@ import (
"strings"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/types"
"github.com/vulcand/oxy/forward"
"github.com/vulcand/oxy/utils"
@ -18,18 +19,16 @@ const (
// Forward the authentication to a external server
func Forward(config *types.Forward, w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
// Ensure our request client does not follow redirects
httpClient := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
if config.TLS != nil {
tlsConfig, err := config.TLS.CreateTLSConfig()
if err != nil {
log.Debugf("Impossible to configure TLS to call %s. Cause %s", config.Address, err)
tracing.SetErrorAndDebugLog(r, "Unable to configure TLS to call %s. Cause %s", config.Address, err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -37,26 +36,28 @@ func Forward(config *types.Forward, w http.ResponseWriter, r *http.Request, next
TLSClientConfig: tlsConfig,
}
}
forwardReq, err := http.NewRequest(http.MethodGet, config.Address, nil)
tracing.LogRequest(tracing.GetSpan(r), forwardReq)
if err != nil {
log.Debugf("Error calling %s. Cause %s", config.Address, err)
tracing.SetErrorAndDebugLog(r, "Error calling %s. Cause %s", config.Address, err)
w.WriteHeader(http.StatusInternalServerError)
return
}
writeHeader(r, forwardReq, config.TrustForwardHeader)
tracing.InjectRequestHeaders(forwardReq)
forwardResponse, forwardErr := httpClient.Do(forwardReq)
if forwardErr != nil {
log.Debugf("Error calling %s. Cause: %s", config.Address, forwardErr)
tracing.SetErrorAndDebugLog(r, "Error calling %s. Cause: %s", config.Address, forwardErr)
w.WriteHeader(http.StatusInternalServerError)
return
}
body, readError := ioutil.ReadAll(forwardResponse.Body)
if readError != nil {
log.Debugf("Error reading body %s. Cause: %s", config.Address, readError)
tracing.SetErrorAndDebugLog(r, "Error reading body %s. Cause: %s", config.Address, readError)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -72,7 +73,7 @@ func Forward(config *types.Forward, w http.ResponseWriter, r *http.Request, next
if err != nil {
if err != http.ErrNoLocation {
log.Debugf("Error reading response location header %s. Cause: %s", config.Address, err)
tracing.SetErrorAndDebugLog(r, "Error reading response location header %s. Cause: %s", config.Address, err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -86,6 +87,7 @@ func Forward(config *types.Forward, w http.ResponseWriter, r *http.Request, next
w.Header().Add("Set-Cookie", cookie.String())
}
tracing.LogResponseCode(tracing.GetSpan(r), forwardResponse.StatusCode)
w.WriteHeader(forwardResponse.StatusCode)
w.Write(body)
return

View file

@ -7,6 +7,7 @@ import (
"net/http/httptest"
"testing"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/testhelpers"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
@ -23,7 +24,7 @@ func TestForwardAuthFail(t *testing.T) {
Forward: &types.Forward{
Address: server.URL,
},
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -55,7 +56,7 @@ func TestForwardAuthSuccess(t *testing.T) {
Forward: &types.Forward{
Address: server.URL,
},
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -87,7 +88,7 @@ func TestForwardAuthRedirect(t *testing.T) {
Forward: &types.Forward{
Address: authTs.URL,
},
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -130,7 +131,7 @@ func TestForwardAuthCookie(t *testing.T) {
Forward: &types.Forward{
Address: authTs.URL,
},
})
}, &tracing.Tracing{})
assert.NoError(t, err, "there should be no error")
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {