* Auth Proxy: Include additional headers as part of the cache key Auth proxy has support to send additional user attributes as part of the authentication flow. These attributes (e.g. Groups) need to be monitored as part of the process in case of change. This commit changes the way we compute the cache key to include all of the attributes sent as part of the authentication request. That way, if we change any user attributes we'll upsert the user information.
201 lines
4.4 KiB
Go
201 lines
4.4 KiB
Go
package authproxy
|
|
|
|
import (
|
|
"encoding/base32"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
|
"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/smartystreets/goconvey/convey"
|
|
"gopkg.in/macaron.v1"
|
|
)
|
|
|
|
type TestMultiLDAP struct {
|
|
multildap.MultiLDAP
|
|
ID int64
|
|
userCalled bool
|
|
loginCalled bool
|
|
}
|
|
|
|
func (stub *TestMultiLDAP) Login(query *models.LoginUserQuery) (
|
|
*models.ExternalUserInfo, error,
|
|
) {
|
|
stub.loginCalled = true
|
|
result := &models.ExternalUserInfo{
|
|
UserId: stub.ID,
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (stub *TestMultiLDAP) User(login string) (
|
|
*models.ExternalUserInfo,
|
|
error,
|
|
) {
|
|
stub.userCalled = true
|
|
result := &models.ExternalUserInfo{
|
|
UserId: stub.ID,
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func prepareMiddleware(t *testing.T, req *http.Request, store *remotecache.RemoteCache) *AuthProxy {
|
|
t.Helper()
|
|
|
|
ctx := &models.ReqContext{
|
|
Context: &macaron.Context{
|
|
Req: macaron.Request{
|
|
Request: req,
|
|
},
|
|
},
|
|
}
|
|
|
|
auth := New(&Options{
|
|
Store: store,
|
|
Ctx: ctx,
|
|
OrgID: 4,
|
|
})
|
|
|
|
return auth
|
|
}
|
|
|
|
func TestMiddlewareContext(t *testing.T) {
|
|
Convey("auth_proxy helper", t, func() {
|
|
req, _ := http.NewRequest("POST", "http://example.com", nil)
|
|
setting.AuthProxyHeaderName = "X-Killa"
|
|
store := remotecache.NewFakeStore(t)
|
|
|
|
name := "markelog"
|
|
req.Header.Add(setting.AuthProxyHeaderName, name)
|
|
|
|
Convey("when the cache only contains the main header", func() {
|
|
|
|
Convey("with a simple cache key", func() {
|
|
// Set cache key
|
|
key := fmt.Sprintf(CachePrefix, base32.StdEncoding.EncodeToString([]byte(name)))
|
|
store.Set(key, int64(33), 0)
|
|
|
|
// Set up the middleware
|
|
auth := prepareMiddleware(t, req, store)
|
|
id, err := auth.Login()
|
|
|
|
So(auth.getKey(), ShouldEqual, "auth-proxy-sync-ttl:NVQXE23FNRXWO===")
|
|
So(err, ShouldBeNil)
|
|
So(id, ShouldEqual, 33)
|
|
})
|
|
|
|
Convey("when the cache key contains additional headers", func() {
|
|
setting.AuthProxyHeaders = map[string]string{"Groups": "X-WEBAUTH-GROUPS"}
|
|
group := "grafana-core-team"
|
|
req.Header.Add("X-WEBAUTH-GROUPS", group)
|
|
|
|
key := fmt.Sprintf(CachePrefix, base32.StdEncoding.EncodeToString([]byte(name+"-"+group)))
|
|
store.Set(key, int64(33), 0)
|
|
|
|
auth := prepareMiddleware(t, req, store)
|
|
|
|
id, err := auth.Login()
|
|
|
|
So(auth.getKey(), ShouldEqual, "auth-proxy-sync-ttl:NVQXE23FNRXWOLLHOJQWMYLOMEWWG33SMUWXIZLBNU======")
|
|
So(err, ShouldBeNil)
|
|
So(id, ShouldEqual, 33)
|
|
})
|
|
|
|
Convey("when the does not exist", func() {
|
|
})
|
|
})
|
|
|
|
Convey("LDAP", func() {
|
|
Convey("logs in via LDAP", func() {
|
|
bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
|
|
cmd.Result = &models.User{
|
|
Id: 42,
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
isLDAPEnabled = func() bool {
|
|
return true
|
|
}
|
|
|
|
stub := &TestMultiLDAP{
|
|
ID: 42,
|
|
}
|
|
|
|
getLDAPConfig = func() (*ldap.Config, error) {
|
|
config := &ldap.Config{
|
|
Servers: []*ldap.ServerConfig{
|
|
{
|
|
SearchBaseDNs: []string{"BaseDNHere"},
|
|
},
|
|
},
|
|
}
|
|
return config, nil
|
|
}
|
|
|
|
newLDAP = func(servers []*ldap.ServerConfig) multildap.IMultiLDAP {
|
|
return stub
|
|
}
|
|
|
|
defer func() {
|
|
newLDAP = multildap.New
|
|
isLDAPEnabled = ldap.IsEnabled
|
|
getLDAPConfig = ldap.GetConfig
|
|
}()
|
|
|
|
store := remotecache.NewFakeStore(t)
|
|
|
|
auth := prepareMiddleware(t, req, store)
|
|
|
|
id, err := auth.Login()
|
|
|
|
So(err, ShouldBeNil)
|
|
So(id, ShouldEqual, 42)
|
|
So(stub.userCalled, ShouldEqual, true)
|
|
})
|
|
|
|
Convey("gets nice error if ldap is enabled but not configured", func() {
|
|
isLDAPEnabled = func() bool {
|
|
return true
|
|
}
|
|
|
|
getLDAPConfig = func() (*ldap.Config, error) {
|
|
return nil, errors.New("Something went wrong")
|
|
}
|
|
|
|
defer func() {
|
|
newLDAP = multildap.New
|
|
isLDAPEnabled = ldap.IsEnabled
|
|
getLDAPConfig = ldap.GetConfig
|
|
}()
|
|
|
|
store := remotecache.NewFakeStore(t)
|
|
|
|
auth := prepareMiddleware(t, req, store)
|
|
|
|
stub := &TestMultiLDAP{
|
|
ID: 42,
|
|
}
|
|
|
|
newLDAP = func(servers []*ldap.ServerConfig) multildap.IMultiLDAP {
|
|
return stub
|
|
}
|
|
|
|
id, err := auth.Login()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
So(err.Error(), ShouldContainSubstring, "Failed to get the user")
|
|
So(id, ShouldNotEqual, 42)
|
|
So(stub.loginCalled, ShouldEqual, false)
|
|
})
|
|
})
|
|
})
|
|
}
|