grafana/pkg/services/authn/clients/proxy_test.go
Karl Persson b44b6fc5c6
AuthN: Add auth proxy client (#61555)
* AuthN: set up boilerplate for proxy client

* AuthN: Implement Test for proxy client

* AuthN: parse accept list in constructor

* AuthN: add proxy client interface

* AuthN: handle error

* AuthN: Implement the proxy client interface for ldap

* AuthN: change reciever name

* AuthN: add grafana as a proxy client

* AuthN: for error returned

* AuthN: add tests for grafana proxy auth

* AuthN: swap order of grafan and ldap auth

* AuthN: Parse additional proxy headers in proxy client and pass down
2023-01-17 10:07:46 +01:00

173 lines
4.4 KiB
Go

package clients
import (
"context"
"net/http"
"testing"
"github.com/grafana/grafana/pkg/services/authn/authntest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/authn"
"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, 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)
assert.Equal(t, tt.expectedOK, c.Test(context.Background(), tt.req))
})
}
}