Skip to content

Commit

Permalink
refactor: dedicate package and tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Sep 18, 2017
1 parent 783ace6 commit 72b6f3a
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 122 deletions.
2 changes: 1 addition & 1 deletion docs/configuration/entrypoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Otherwise, the response from the auth server is returned.
# Useful with another reverse proxy in front of Traefik.
#
# Optional
# Deafult: false
# Default: false
#
trustForwardHeader = true

Expand Down
45 changes: 2 additions & 43 deletions middlewares/authenticator.go → middlewares/auth/authenticator.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package middlewares
package auth

import (
"fmt"
Expand All @@ -7,7 +7,6 @@ import (
"strings"

goauth "github.com/abbot/go-http-auth"
"github.com/containous/traefik/auth"
"github.com/containous/traefik/log"
"github.com/containous/traefik/types"
"github.com/urfave/negroni"
Expand Down Expand Up @@ -64,52 +63,12 @@ func NewAuthenticator(authConfig *types.Auth) (*Authenticator, error) {
})
} else if authConfig.Forward != nil {
authenticator.handler = negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
auth.Forward(authConfig.Forward, w, r, next)
Forward(authConfig.Forward, w, r, next)
})
}
return &authenticator, nil
}

func parserBasicUsers(basic *types.Basic) (map[string]string, error) {
var userStrs []string
if basic.UsersFile != "" {
var err error
if userStrs, err = getLinesFromFile(basic.UsersFile); err != nil {
return nil, err
}
}
userStrs = append(basic.Users, userStrs...)
userMap := make(map[string]string)
for _, user := range userStrs {
split := strings.Split(user, ":")
if len(split) != 2 {
return nil, fmt.Errorf("Error parsing Authenticator user: %v", user)
}
userMap[split[0]] = split[1]
}
return userMap, nil
}

func parserDigestUsers(digest *types.Digest) (map[string]string, error) {
var userStrs []string
if digest.UsersFile != "" {
var err error
if userStrs, err = getLinesFromFile(digest.UsersFile); err != nil {
return nil, err
}
}
userStrs = append(digest.Users, userStrs...)
userMap := make(map[string]string)
for _, user := range userStrs {
split := strings.Split(user, ":")
if len(split) != 3 {
return nil, fmt.Errorf("Error parsing Authenticator user: %v", user)
}
userMap[split[0]+":"+split[1]] = split[2]
}
return userMap, nil
}

func getLinesFromFile(filename string) ([]string, error) {
dat, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package middlewares
package auth

import (
"fmt"
Expand Down Expand Up @@ -157,7 +157,7 @@ func TestDigestAuthFail(t *testing.T) {
}

func TestBasicAuthUserHeader(t *testing.T) {
authMiddleware, err := NewAuthenticator(&types.Auth{
middleware, err := NewAuthenticator(&types.Auth{
Basic: &types.Basic{
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
},
Expand All @@ -169,7 +169,7 @@ func TestBasicAuthUserHeader(t *testing.T) {
assert.Equal(t, "test", r.Header["X-Webauth-User"][0], "auth user should be set")
fmt.Fprintln(w, "traefik")
})
n := negroni.New(authMiddleware)
n := negroni.New(middleware)
n.UseHandler(handler)
ts := httptest.NewServer(n)
defer ts.Close()
Expand All @@ -186,67 +186,3 @@ func TestBasicAuthUserHeader(t *testing.T) {
assert.NoError(t, err, "there should be no error")
assert.Equal(t, "traefik\n", string(body), "they should be equal")
}

func TestForwardAuthFail(t *testing.T) {
authTs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Forbidden", http.StatusForbidden)
}))
defer authTs.Close()

authMiddleware, err := NewAuthenticator(&types.Auth{
Forward: &types.Forward{
Address: authTs.URL,
},
})
assert.NoError(t, err, "there should be no error")

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "traefik")
})
n := negroni.New(authMiddleware)
n.UseHandler(handler)
ts := httptest.NewServer(n)
defer ts.Close()

client := &http.Client{}
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
res, err := client.Do(req)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, http.StatusForbidden, res.StatusCode, "they should be equal")

body, err := ioutil.ReadAll(res.Body)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, "Forbidden\n", string(body), "they should be equal")
}

func TestForwardAuthSuccess(t *testing.T) {
authTs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Success")
}))
defer authTs.Close()

authMiddleware, err := NewAuthenticator(&types.Auth{
Forward: &types.Forward{
Address: authTs.URL,
},
})
assert.NoError(t, err, "there should be no error")

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "traefik")
})
n := negroni.New(authMiddleware)
n.UseHandler(handler)
ts := httptest.NewServer(n)
defer ts.Close()

client := &http.Client{}
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
res, err := client.Do(req)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, http.StatusOK, res.StatusCode, "they should be equal")

body, err := ioutil.ReadAll(res.Body)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, "traefik\n", string(body), "they should be equal")
}
17 changes: 9 additions & 8 deletions auth/forward.go → middlewares/auth/forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,26 @@ func writeHeader(req *http.Request, forwardReq *http.Request, trustForwardHeader
clientIP = strings.Join(prior, ", ") + ", " + clientIP
}
}
req.Header.Set(forward.XForwardedFor, clientIP)
forwardReq.Header.Set(forward.XForwardedFor, clientIP)
}

if xfp := req.Header.Get(forward.XForwardedProto); xfp != "" && trustForwardHeader {
req.Header.Set(forward.XForwardedProto, xfp)
forwardReq.Header.Set(forward.XForwardedProto, xfp)
} else if req.TLS != nil {
req.Header.Set(forward.XForwardedProto, "https")
forwardReq.Header.Set(forward.XForwardedProto, "https")
} else {
req.Header.Set(forward.XForwardedProto, "http")
forwardReq.Header.Set(forward.XForwardedProto, "http")
}

if xfp := req.Header.Get(forward.XForwardedPort); xfp != "" && trustForwardHeader {
req.Header.Set(forward.XForwardedPort, xfp)
forwardReq.Header.Set(forward.XForwardedPort, xfp)
}

if xfh := req.Header.Get(forward.XForwardedHost); xfh != "" && trustForwardHeader {
req.Header.Set(forward.XForwardedHost, xfh)
forwardReq.Header.Set(forward.XForwardedHost, xfh)
} else if req.Host != "" {
req.Header.Set(forward.XForwardedHost, req.Host)
forwardReq.Header.Set(forward.XForwardedHost, req.Host)
} else {
forwardReq.Header.Del(forward.XForwardedHost)
}

}
162 changes: 162 additions & 0 deletions middlewares/auth/forward_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package auth

import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"

"github.com/containous/traefik/testhelpers"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
"github.com/urfave/negroni"
)

func TestForwardAuthFail(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Forbidden", http.StatusForbidden)
}))
defer server.Close()

middleware, err := NewAuthenticator(&types.Auth{
Forward: &types.Forward{
Address: server.URL,
},
})
assert.NoError(t, err, "there should be no error")

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "traefik")
})
n := negroni.New(middleware)
n.UseHandler(handler)
ts := httptest.NewServer(n)
defer ts.Close()

client := &http.Client{}
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
res, err := client.Do(req)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, http.StatusForbidden, res.StatusCode, "they should be equal")

body, err := ioutil.ReadAll(res.Body)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, "Forbidden\n", string(body), "they should be equal")
}

func TestForwardAuthSuccess(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Success")
}))
defer server.Close()

middleware, err := NewAuthenticator(&types.Auth{
Forward: &types.Forward{
Address: server.URL,
},
})
assert.NoError(t, err, "there should be no error")

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "traefik")
})
n := negroni.New(middleware)
n.UseHandler(handler)
ts := httptest.NewServer(n)
defer ts.Close()

client := &http.Client{}
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
res, err := client.Do(req)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, http.StatusOK, res.StatusCode, "they should be equal")

body, err := ioutil.ReadAll(res.Body)
assert.NoError(t, err, "there should be no error")
assert.Equal(t, "traefik\n", string(body), "they should be equal")
}

func Test_writeHeader(t *testing.T) {

testCases := []struct {
name string
headers map[string]string
trustForwardHeader bool
emptyHost bool
expectedHeaders map[string]string
}{
{
name: "trust Forward Header",
headers: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "fii.bir",
},
trustForwardHeader: true,
expectedHeaders: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "fii.bir",
},
},
{
name: "not trust Forward Header",
headers: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "fii.bir",
},
trustForwardHeader: false,
expectedHeaders: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "foo.bar",
},
},
{
name: "trust Forward Header with empty Host",
headers: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "fii.bir",
},
trustForwardHeader: true,
emptyHost: true,
expectedHeaders: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "fii.bir",
},
},
{
name: "not trust Forward Header with empty Host",
headers: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "fii.bir",
},
trustForwardHeader: false,
emptyHost: true,
expectedHeaders: map[string]string{
"Accept": "application/json",
"X-Forwarded-Host": "",
},
},
}

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {

req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar", nil)
for key, value := range test.headers {
req.Header.Set(key, value)
}

if test.emptyHost {
req.Host = ""
}

forwardReq := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar", nil)

writeHeader(req, forwardReq, test.trustForwardHeader)

for key, value := range test.expectedHeaders {
assert.Equal(t, value, forwardReq.Header.Get(key))
}
})
}
}

0 comments on commit 72b6f3a

Please sign in to comment.