mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 16:15:42 -06:00
* 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
173 lines
4.4 KiB
Go
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))
|
|
})
|
|
}
|
|
}
|