refactor authproxy & ldap integration, address comments
This commit is contained in:
@@ -44,11 +44,49 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
|
||||
// if this session has already been authenticated by authProxy just load the user
|
||||
sessProxyValue := ctx.Session.Get(AUTH_PROXY_SESSION_VAR)
|
||||
if sessProxyValue != nil && sessProxyValue.(string) == proxyHeaderValue && getRequestUserId(ctx) > 0 {
|
||||
query.UserId = getRequestUserId(ctx)
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
ctx.Handle(500, "Failed to find user", err)
|
||||
return true
|
||||
// if we're using ldap, sync user periodically
|
||||
if setting.LdapEnabled {
|
||||
syncQuery := &m.LoginUserQuery{
|
||||
ReqContext: ctx,
|
||||
Username: proxyHeaderValue,
|
||||
}
|
||||
|
||||
if err := syncGrafanaUserWithLdapUser(syncQuery); err != nil {
|
||||
if err == login.ErrInvalidCredentials {
|
||||
ctx.Handle(500, "Unable to authenticate user", err)
|
||||
return false
|
||||
}
|
||||
|
||||
ctx.Handle(500, "Failed to sync user", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
query.UserId = getRequestUserId(ctx)
|
||||
// if we're using ldap, pass authproxy login name to ldap user sync
|
||||
} else if setting.LdapEnabled {
|
||||
syncQuery := &m.LoginUserQuery{
|
||||
ReqContext: ctx,
|
||||
Username: proxyHeaderValue,
|
||||
}
|
||||
|
||||
if err := syncGrafanaUserWithLdapUser(syncQuery); err != nil {
|
||||
if err == login.ErrInvalidCredentials {
|
||||
ctx.Handle(500, "Unable to authenticate user", err)
|
||||
return false
|
||||
}
|
||||
|
||||
ctx.Handle(500, "Failed to sync user", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if syncQuery.User == nil {
|
||||
ctx.Handle(500, "Failed to sync user", nil)
|
||||
return false
|
||||
}
|
||||
|
||||
query.UserId = syncQuery.User.Id
|
||||
// no ldap, just use the info we have
|
||||
} else {
|
||||
extUser := &m.ExternalUserInfo{
|
||||
AuthModule: "authproxy",
|
||||
@@ -84,39 +122,28 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
|
||||
}
|
||||
|
||||
query.UserId = cmd.Result.Id
|
||||
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
ctx.Handle(500, "Failed to find user", err)
|
||||
return true
|
||||
}
|
||||
|
||||
// Make sure that we cannot share a session between different users!
|
||||
if getRequestUserId(ctx) > 0 && getRequestUserId(ctx) != query.Result.UserId {
|
||||
// remove session
|
||||
if err := ctx.Session.Destory(ctx.Context); err != nil {
|
||||
log.Error(3, "Failed to destroy session, err")
|
||||
}
|
||||
|
||||
// initialize a new session
|
||||
if err := ctx.Session.Start(ctx.Context); err != nil {
|
||||
log.Error(3, "Failed to start session", err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Session.Set(AUTH_PROXY_SESSION_VAR, proxyHeaderValue)
|
||||
}
|
||||
|
||||
// When ldap is enabled, sync userinfo and org roles
|
||||
if err := syncGrafanaUserWithLdapUser(ctx, query); err != nil {
|
||||
if err == login.ErrInvalidCredentials {
|
||||
ctx.Handle(500, "Unable to authenticate user", err)
|
||||
return false
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
ctx.Handle(500, "Failed to find user", err)
|
||||
return true
|
||||
}
|
||||
|
||||
// Make sure that we cannot share a session between different users!
|
||||
if getRequestUserId(ctx) > 0 && getRequestUserId(ctx) != query.Result.UserId {
|
||||
// remove session
|
||||
if err := ctx.Session.Destory(ctx.Context); err != nil {
|
||||
log.Error(3, "Failed to destroy session, err")
|
||||
}
|
||||
|
||||
ctx.Handle(500, "Failed to sync user", err)
|
||||
return false
|
||||
// initialize a new session
|
||||
if err := ctx.Session.Start(ctx.Context); err != nil {
|
||||
log.Error(3, "Failed to start session", err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Session.Set(AUTH_PROXY_SESSION_VAR, proxyHeaderValue)
|
||||
|
||||
ctx.SignedInUser = query.Result
|
||||
ctx.IsSignedIn = true
|
||||
ctx.Session.Set(session.SESS_KEY_USERID, ctx.UserId)
|
||||
@@ -124,29 +151,29 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var syncGrafanaUserWithLdapUser = func(ctx *m.ReqContext, query *m.GetSignedInUserQuery) error {
|
||||
if !setting.LdapEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
var syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
|
||||
expireEpoch := time.Now().Add(time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute).Unix()
|
||||
|
||||
var lastLdapSync int64
|
||||
if lastLdapSyncInSession := ctx.Session.Get(session.SESS_KEY_LASTLDAPSYNC); lastLdapSyncInSession != nil {
|
||||
if lastLdapSyncInSession := query.ReqContext.Session.Get(session.SESS_KEY_LASTLDAPSYNC); lastLdapSyncInSession != nil {
|
||||
lastLdapSync = lastLdapSyncInSession.(int64)
|
||||
}
|
||||
|
||||
if lastLdapSync < expireEpoch {
|
||||
ldapCfg := login.LdapCfg
|
||||
|
||||
if len(ldapCfg.Servers) < 1 {
|
||||
return fmt.Errorf("No LDAP servers available")
|
||||
}
|
||||
|
||||
for _, server := range ldapCfg.Servers {
|
||||
author := login.NewLdapAuthenticator(server)
|
||||
if err := author.SyncSignedInUser(ctx, query.Result); err != nil {
|
||||
if err := author.SyncUser(query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Session.Set(session.SESS_KEY_LASTLDAPSYNC, time.Now().Unix())
|
||||
query.ReqContext.Session.Set(session.SESS_KEY_LASTLDAPSYNC, time.Now().Unix())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -26,57 +26,71 @@ func TestAuthProxyWithLdapEnabled(t *testing.T) {
|
||||
return &mockLdapAuther
|
||||
}
|
||||
|
||||
signedInUser := m.SignedInUser{}
|
||||
query := m.GetSignedInUserQuery{Result: &signedInUser}
|
||||
|
||||
Convey("When session variable lastLdapSync not set, call syncSignedInUser and set lastLdapSync", func() {
|
||||
Convey("When user logs in, call SyncUser", func() {
|
||||
// arrange
|
||||
sess := mockSession{}
|
||||
sess := newMockSession()
|
||||
ctx := m.ReqContext{Session: &sess}
|
||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeNil)
|
||||
|
||||
// act
|
||||
syncGrafanaUserWithLdapUser(&ctx, &query)
|
||||
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
|
||||
ReqContext: &ctx,
|
||||
Username: "test",
|
||||
})
|
||||
|
||||
// assert
|
||||
So(mockLdapAuther.syncSignedInUserCalled, ShouldBeTrue)
|
||||
So(mockLdapAuther.syncUserCalled, ShouldBeTrue)
|
||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, 0)
|
||||
})
|
||||
|
||||
Convey("When session variable not expired, don't sync and don't change session var", func() {
|
||||
// arrange
|
||||
sess := mockSession{}
|
||||
sess := newMockSession()
|
||||
ctx := m.ReqContext{Session: &sess}
|
||||
now := time.Now().Unix()
|
||||
sess.Set(session.SESS_KEY_LASTLDAPSYNC, now)
|
||||
sess.Set(AUTH_PROXY_SESSION_VAR, "test")
|
||||
|
||||
// act
|
||||
syncGrafanaUserWithLdapUser(&ctx, &query)
|
||||
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
|
||||
ReqContext: &ctx,
|
||||
Username: "test",
|
||||
})
|
||||
|
||||
// assert
|
||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldEqual, now)
|
||||
So(mockLdapAuther.syncSignedInUserCalled, ShouldBeFalse)
|
||||
So(mockLdapAuther.syncUserCalled, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("When lastldapsync is expired, session variable should be updated", func() {
|
||||
// arrange
|
||||
sess := mockSession{}
|
||||
sess := newMockSession()
|
||||
ctx := m.ReqContext{Session: &sess}
|
||||
expiredTime := time.Now().Add(time.Duration(-120) * time.Minute).Unix()
|
||||
sess.Set(session.SESS_KEY_LASTLDAPSYNC, expiredTime)
|
||||
sess.Set(AUTH_PROXY_SESSION_VAR, "test")
|
||||
|
||||
// act
|
||||
syncGrafanaUserWithLdapUser(&ctx, &query)
|
||||
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
|
||||
ReqContext: &ctx,
|
||||
Username: "test",
|
||||
})
|
||||
|
||||
// assert
|
||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, expiredTime)
|
||||
So(mockLdapAuther.syncSignedInUserCalled, ShouldBeTrue)
|
||||
So(mockLdapAuther.syncUserCalled, ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type mockSession struct {
|
||||
value interface{}
|
||||
value map[interface{}]interface{}
|
||||
}
|
||||
|
||||
func newMockSession() mockSession {
|
||||
session := mockSession{}
|
||||
session.value = make(map[interface{}]interface{})
|
||||
return session
|
||||
}
|
||||
|
||||
func (s *mockSession) Start(c *macaron.Context) error {
|
||||
@@ -84,15 +98,16 @@ func (s *mockSession) Start(c *macaron.Context) error {
|
||||
}
|
||||
|
||||
func (s *mockSession) Set(k interface{}, v interface{}) error {
|
||||
s.value = v
|
||||
s.value[k] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *mockSession) Get(k interface{}) interface{} {
|
||||
return s.value
|
||||
return s.value[k]
|
||||
}
|
||||
|
||||
func (s *mockSession) Delete(k interface{}) interface{} {
|
||||
delete(s.value, k)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -113,15 +128,15 @@ func (s *mockSession) RegenerateId(c *macaron.Context) error {
|
||||
}
|
||||
|
||||
type mockLdapAuthenticator struct {
|
||||
syncSignedInUserCalled bool
|
||||
syncUserCalled bool
|
||||
}
|
||||
|
||||
func (a *mockLdapAuthenticator) Login(query *m.LoginUserQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *mockLdapAuthenticator) SyncSignedInUser(ctx *m.ReqContext, signedInUser *m.SignedInUser) error {
|
||||
a.syncSignedInUserCalled = true
|
||||
func (a *mockLdapAuthenticator) SyncUser(query *m.LoginUserQuery) error {
|
||||
a.syncUserCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
setting.AuthProxyEnabled = true
|
||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
||||
setting.AuthProxyHeaderProperty = "username"
|
||||
setting.LdapEnabled = false
|
||||
|
||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||
query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
|
||||
@@ -203,6 +204,7 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
||||
setting.AuthProxyHeaderProperty = "username"
|
||||
setting.AuthProxyAutoSignUp = true
|
||||
setting.LdapEnabled = false
|
||||
|
||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||
if query.UserId > 0 {
|
||||
@@ -333,8 +335,9 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
setting.LdapEnabled = true
|
||||
|
||||
called := false
|
||||
syncGrafanaUserWithLdapUser = func(ctx *m.ReqContext, query *m.GetSignedInUserQuery) error {
|
||||
syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
|
||||
called = true
|
||||
query.User = &m.User{Id: 32}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user