grafana/pkg/services/contexthandler/authproxy/authproxy_test.go
Sergey Kostrukov 1dca39fb91
Auth Proxy: encoding of non-ASCII headers (#44797)
* Decode auth proxy headers using URL encoding

* Header encoding configuration via settings file

* Rename configuration setting to headers_encoded

* Quoted-printable encoding

* Tests for AuthProxy

* Fix encoding name

* Remove authproxy init
2022-03-04 04:58:27 -05:00

220 lines
5.5 KiB
Go

package authproxy
import (
"context"
"errors"
"fmt"
"net/http"
"testing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/remotecache"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/multildap"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const hdrName = "markelog"
func prepareMiddleware(t *testing.T, remoteCache *remotecache.RemoteCache, configureReq func(*http.Request, *setting.Cfg)) *AuthProxy {
t.Helper()
req, err := http.NewRequest("POST", "http://example.com", nil)
require.NoError(t, err)
cfg := setting.NewCfg()
if configureReq != nil {
configureReq(req, cfg)
} else {
cfg.AuthProxyHeaderName = "X-Killa"
req.Header.Set(cfg.AuthProxyHeaderName, hdrName)
}
ctx := &models.ReqContext{
Context: &web.Context{Req: req},
}
auth := New(cfg, &Options{
RemoteCache: remoteCache,
Ctx: ctx,
OrgID: 4,
})
return auth
}
func TestMiddlewareContext(t *testing.T) {
logger := log.New("test")
cache := remotecache.NewFakeStore(t)
t.Run("When the cache only contains the main header with a simple cache key", func(t *testing.T) {
const id int64 = 33
// Set cache key
h, err := HashCacheKey(hdrName)
require.NoError(t, err)
key := fmt.Sprintf(CachePrefix, h)
err = cache.Set(context.Background(), key, id, 0)
require.NoError(t, err)
// Set up the middleware
auth := prepareMiddleware(t, cache, nil)
gotKey, err := auth.getKey()
require.NoError(t, err)
assert.Equal(t, key, gotKey)
gotID, err := auth.Login(logger, false)
require.NoError(t, err)
assert.Equal(t, id, gotID)
})
t.Run("When the cache key contains additional headers", func(t *testing.T) {
const id int64 = 33
const group = "grafana-core-team"
const role = "Admin"
h, err := HashCacheKey(hdrName + "-" + group + "-" + role)
require.NoError(t, err)
key := fmt.Sprintf(CachePrefix, h)
err = cache.Set(context.Background(), key, id, 0)
require.NoError(t, err)
auth := prepareMiddleware(t, cache, func(req *http.Request, cfg *setting.Cfg) {
cfg.AuthProxyHeaderName = "X-Killa"
cfg.AuthProxyHeaders = map[string]string{"Groups": "X-WEBAUTH-GROUPS", "Role": "X-WEBAUTH-ROLE"}
req.Header.Set(cfg.AuthProxyHeaderName, hdrName)
req.Header.Set("X-WEBAUTH-GROUPS", group)
req.Header.Set("X-WEBAUTH-ROLE", role)
})
assert.Equal(t, "auth-proxy-sync-ttl:f5acfffd56daac98d502ef8c8b8c5d56", key)
gotID, err := auth.Login(logger, false)
require.NoError(t, err)
assert.Equal(t, id, gotID)
})
}
func TestMiddlewareContext_ldap(t *testing.T) {
logger := log.New("test")
t.Run("Logs in via LDAP", func(t *testing.T) {
const id int64 = 42
bus.AddHandler("test", func(ctx context.Context, cmd *models.UpsertUserCommand) error {
cmd.Result = &models.User{
Id: id,
}
return nil
})
origIsLDAPEnabled := isLDAPEnabled
origGetLDAPConfig := getLDAPConfig
origNewLDAP := newLDAP
t.Cleanup(func() {
newLDAP = origNewLDAP
isLDAPEnabled = origIsLDAPEnabled
getLDAPConfig = origGetLDAPConfig
})
isLDAPEnabled = func(*setting.Cfg) bool {
return true
}
stub := &multildap.MultiLDAPmock{
ID: id,
}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
config := &ldap.Config{
Servers: []*ldap.ServerConfig{
{
SearchBaseDNs: []string{"BaseDNHere"},
},
},
}
return config, nil
}
newLDAP = func(servers []*ldap.ServerConfig) multildap.IMultiLDAP {
return stub
}
cache := remotecache.NewFakeStore(t)
auth := prepareMiddleware(t, cache, nil)
gotID, err := auth.Login(logger, false)
require.NoError(t, err)
assert.Equal(t, id, gotID)
assert.True(t, stub.UserCalled)
})
t.Run("Gets nice error if LDAP is enabled, but not configured", func(t *testing.T) {
const id int64 = 42
origIsLDAPEnabled := isLDAPEnabled
origNewLDAP := newLDAP
origGetLDAPConfig := getLDAPConfig
t.Cleanup(func() {
isLDAPEnabled = origIsLDAPEnabled
newLDAP = origNewLDAP
getLDAPConfig = origGetLDAPConfig
})
isLDAPEnabled = func(*setting.Cfg) bool {
return true
}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return nil, errors.New("something went wrong")
}
cache := remotecache.NewFakeStore(t)
auth := prepareMiddleware(t, cache, nil)
stub := &multildap.MultiLDAPmock{
ID: id,
}
newLDAP = func(servers []*ldap.ServerConfig) multildap.IMultiLDAP {
return stub
}
gotID, err := auth.Login(logger, false)
require.EqualError(t, err, "failed to get the user")
assert.NotEqual(t, id, gotID)
assert.False(t, stub.LoginCalled)
})
}
func TestDecodeHeader(t *testing.T) {
cache := remotecache.NewFakeStore(t)
t.Run("should not decode header if not enabled in settings", func(t *testing.T) {
auth := prepareMiddleware(t, cache, func(req *http.Request, cfg *setting.Cfg) {
cfg.AuthProxyHeaderName = "X-WEBAUTH-USER"
cfg.AuthProxyHeadersEncoded = false
req.Header.Set(cfg.AuthProxyHeaderName, "M=C3=BCnchen")
})
assert.Equal(t, "M=C3=BCnchen", auth.header)
})
t.Run("should decode header if enabled in settings", func(t *testing.T) {
auth := prepareMiddleware(t, cache, func(req *http.Request, cfg *setting.Cfg) {
cfg.AuthProxyHeaderName = "X-WEBAUTH-USER"
cfg.AuthProxyHeadersEncoded = true
req.Header.Set(cfg.AuthProxyHeaderName, "M=C3=BCnchen")
})
assert.Equal(t, "München", auth.header)
})
}