The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/authn/clients/proxy_test.go

190 lines
4.9 KiB

package clients
import (
"context"
"errors"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/authn/authntest"
"github.com/grafana/grafana/pkg/services/user/usertest"
"github.com/grafana/grafana/pkg/setting"
)
func TestProxy_Authenticate(t *testing.T) {
type testCase struct {
desc string
req *authn.Request
ips string
proxyHeader string
proxyHeaders map[string]string
expectedErr error
expectedUsername string
expectedAdditional map[string]string
}
tests := []testCase{
{
desc: "should authenticate using passed in proxy client",
ips: "127.0.0.1",
req: &authn.Request{
HTTPRequest: &http.Request{
Header: map[string][]string{
"X-Username": {"username"},
"X-Name": {"name"},
"X-Email": {"email"},
"X-Login": {"login"},
"X-Role": {"Viewer"},
"X-Group": {"grp1,grp2"},
},
RemoteAddr: "127.0.0.1:333",
},
},
proxyHeader: "X-Username",
proxyHeaders: map[string]string{
proxyFieldName: "X-Name",
proxyFieldEmail: "X-Email",
proxyFieldLogin: "X-Login",
proxyFieldRole: "X-Role",
proxyFieldGroups: "X-Group",
},
expectedUsername: "username",
expectedAdditional: map[string]string{
proxyFieldName: "name",
proxyFieldEmail: "email",
proxyFieldLogin: "login",
proxyFieldRole: "Viewer",
proxyFieldGroups: "grp1,grp2",
},
},
{
desc: "should fail when proxy header is empty",
req: &authn.Request{
HTTPRequest: &http.Request{Header: map[string][]string{
"X-Username": {""},
"X-Name": {"name"},
"X-Email": {"email"},
"X-Login": {"login"},
"X-Role": {"Viewer"},
"X-Group": {"grp1,grp2"},
}},
},
proxyHeader: "X-Username",
proxyHeaders: map[string]string{
proxyFieldName: "X-Name",
proxyFieldEmail: "X-Email",
proxyFieldLogin: "X-Login",
proxyFieldRole: "X-Role",
proxyFieldGroups: "X-Group",
},
expectedErr: errEmptyProxyHeader,
},
{
desc: "should fail when caller ip is not in accept list",
req: &authn.Request{
HTTPRequest: &http.Request{
Header: map[string][]string{},
RemoteAddr: "127.0.0.2:333",
},
},
ips: "127.0.0.1",
expectedErr: errNotAcceptedIP,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
cfg := setting.NewCfg()
cfg.AuthProxyHeaderName = "X-Username"
cfg.AuthProxyHeaders = tt.proxyHeaders
cfg.AuthProxyWhitelist = tt.ips
calledUsername := ""
var calledAdditional map[string]string
proxyClient := authntest.MockProxyClient{AuthenticateProxyFunc: func(ctx context.Context, r *authn.Request, username string, additional map[string]string) (*authn.Identity, error) {
calledUsername = username
calledAdditional = additional
return nil, nil
}}
c, err := ProvideProxy(cfg, fakeCache{expectedErr: errors.New("")}, usertest.NewUserServiceFake(), proxyClient)
require.NoError(t, err)
_, err = c.Authenticate(context.Background(), tt.req)
assert.ErrorIs(t, err, tt.expectedErr)
assert.Equal(t, tt.expectedUsername, calledUsername)
assert.EqualValues(t, tt.expectedAdditional, calledAdditional)
})
}
}
func TestProxy_Test(t *testing.T) {
type testCase struct {
desc string
req *authn.Request
expectedOK bool
}
tests := []testCase{
{
desc: "should return true when proxy header exists",
req: &authn.Request{
HTTPRequest: &http.Request{
Header: map[string][]string{"Proxy-Header": {"some value"}},
},
},
expectedOK: true,
},
{
desc: "should return false when proxy header exists but has no value",
req: &authn.Request{
HTTPRequest: &http.Request{
Header: map[string][]string{"Proxy-Header": {""}},
},
},
expectedOK: false,
},
{
desc: "should return false when no proxy header is set on request",
req: &authn.Request{
HTTPRequest: &http.Request{Header: map[string][]string{}},
},
expectedOK: false,
},
{
desc: "should return false when no http request is present",
req: &authn.Request{},
expectedOK: false,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
cfg := setting.NewCfg()
cfg.AuthProxyHeaderName = "Proxy-Header"
c, _ := ProvideProxy(cfg, nil, nil, nil)
assert.Equal(t, tt.expectedOK, c.Test(context.Background(), tt.req))
})
}
}
var _ proxyCache = new(fakeCache)
type fakeCache struct {
expectedErr error
expectedItem []byte
}
func (f fakeCache) Get(ctx context.Context, key string) ([]byte, error) {
return f.expectedItem, f.expectedErr
}
func (f fakeCache) Set(ctx context.Context, key string, value []byte, expire time.Duration) error {
return f.expectedErr
}