diff --git a/pkg/login/ext_user.go b/pkg/login/ext_user.go index 02f70b3e00b..82ebcf481b9 100644 --- a/pkg/login/ext_user.go +++ b/pkg/login/ext_user.go @@ -9,7 +9,7 @@ import ( "github.com/grafana/grafana/pkg/services/quota" ) -func UpsertUser(ctx *m.ReqContext, cmd *m.UpsertUserCommand) error { +var UpsertUser = func(ctx *m.ReqContext, cmd *m.UpsertUserCommand) error { extUser := cmd.ExternalUser userQuery := m.GetUserByAuthInfoQuery{ @@ -87,14 +87,26 @@ func createUser(extUser *m.ExternalUserInfo) (*m.User, error) { func updateUser(user *m.User, extUser *m.ExternalUserInfo) error { // sync user info - if user.Login != extUser.Login || user.Email != extUser.Email || user.Name != extUser.Name { - log.Debug("Syncing user info", "id", user.Id, "login", extUser.Login, "email", extUser.Email) - updateCmd := m.UpdateUserCommand{ - UserId: user.Id, - Login: extUser.Login, - Email: extUser.Email, - Name: extUser.Name, - } + updateCmd := m.UpdateUserCommand{ + UserId: user.Id, + } + needsUpdate := false + + if extUser.Login != "" && extUser.Login != user.Login { + updateCmd.Login = extUser.Login + needsUpdate = true + } + if extUser.Email != "" && extUser.Email != user.Email { + updateCmd.Email = extUser.Email + needsUpdate = true + } + if extUser.Name != "" && extUser.Name != user.Name { + updateCmd.Name = extUser.Name + needsUpdate = true + } + + if needsUpdate { + log.Debug("Syncing user info", "id", user.Id, "update", updateCmd) err := bus.Dispatch(&updateCmd) if err != nil { return err diff --git a/pkg/middleware/auth_proxy.go b/pkg/middleware/auth_proxy.go index 10a3e549112..424d0719f50 100644 --- a/pkg/middleware/auth_proxy.go +++ b/pkg/middleware/auth_proxy.go @@ -3,6 +3,7 @@ package middleware import ( "fmt" "net" + "net/mail" "strings" "time" @@ -14,6 +15,8 @@ import ( "github.com/grafana/grafana/pkg/setting" ) +var AUTH_PROXY_SESSION_VAR = "authProxyHeaderValue" + func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { if !setting.AuthProxyEnabled { return false @@ -30,51 +33,75 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { return true } - query := getSignedInUserQueryForProxyAuth(proxyHeaderValue) - query.OrgId = orgID - if err := bus.Dispatch(query); err != nil { - if err != m.ErrUserNotFound { - ctx.Handle(500, "Failed to find user specified in auth proxy header", err) - return true - } - - if !setting.AuthProxyAutoSignUp { - return false - } - - cmd := getCreateUserCommandForProxyAuth(proxyHeaderValue) - if setting.LdapEnabled { - cmd.SkipOrgSetup = true - } - - if err := bus.Dispatch(cmd); err != nil { - ctx.Handle(500, "Failed to create user specified in auth proxy header", err) - return true - } - query = &m.GetSignedInUserQuery{UserId: cmd.Result.Id, OrgId: orgID} - if err := bus.Dispatch(query); err != nil { - ctx.Handle(500, "Failed find user after creation", err) - return true - } - } - // initialize session if err := ctx.Session.Start(ctx.Context); err != nil { log.Error(3, "Failed to start session", err) return false } - // 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") + query := &m.GetSignedInUserQuery{OrgId: orgID} + + // 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 + } + } else { + extUser := m.ExternalUserInfo{ + AuthModule: "authproxy", + AuthId: proxyHeaderValue, } - // initialize a new session - if err := ctx.Session.Start(ctx.Context); err != nil { - log.Error(3, "Failed to start session", err) + if setting.AuthProxyHeaderProperty == "username" { + extUser.Login = proxyHeaderValue + + // only set Email if it can be parsed as an email address + emailAddr, emailErr := mail.ParseAddress(proxyHeaderValue) + if emailErr == nil { + extUser.Email = emailAddr.Address + } + } else if setting.AuthProxyHeaderProperty == "email" { + extUser.Email = proxyHeaderValue + extUser.Login = proxyHeaderValue + } else { + ctx.Handle(500, "Auth proxy header property invalid", nil) } + + // add/update user in grafana + userQuery := &m.UpsertUserCommand{ + ExternalUser: &extUser, + SignupAllowed: setting.AuthProxyAutoSignUp, + } + err := login.UpsertUser(ctx, userQuery) + if err != nil { + ctx.Handle(500, "Failed to login as user specified in auth proxy header", err) + return true + } + + query.UserId = userQuery.User.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 @@ -143,29 +170,3 @@ func checkAuthenticationProxy(remoteAddr string, proxyHeaderValue string) error return fmt.Errorf("Request for user (%s) from %s is not from the authentication proxy", proxyHeaderValue, sourceIP) } - -func getSignedInUserQueryForProxyAuth(headerVal string) *m.GetSignedInUserQuery { - query := m.GetSignedInUserQuery{} - if setting.AuthProxyHeaderProperty == "username" { - query.Login = headerVal - } else if setting.AuthProxyHeaderProperty == "email" { - query.Email = headerVal - } else { - panic("Auth proxy header property invalid") - } - return &query -} - -func getCreateUserCommandForProxyAuth(headerVal string) *m.CreateUserCommand { - cmd := m.CreateUserCommand{} - if setting.AuthProxyHeaderProperty == "username" { - cmd.Login = headerVal - cmd.Email = headerVal - } else if setting.AuthProxyHeaderProperty == "email" { - cmd.Email = headerVal - cmd.Login = headerVal - } else { - panic("Auth proxy header property invalid") - } - return &cmd -} diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index 09c38bed644..b7a6afa47aa 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -9,6 +9,7 @@ import ( ms "github.com/go-macaron/session" "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/login" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/session" "github.com/grafana/grafana/pkg/setting" @@ -182,6 +183,11 @@ func TestMiddlewareContext(t *testing.T) { return nil }) + login.UpsertUser = func(ctx *m.ReqContext, cmd *m.UpsertUserCommand) error { + cmd.User = &m.User{Id: 12} + return nil + } + sc.fakeReq("GET", "/") sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") sc.exec() @@ -208,10 +214,10 @@ func TestMiddlewareContext(t *testing.T) { } }) - bus.AddHandler("test", func(cmd *m.CreateUserCommand) error { - cmd.Result = m.User{Id: 33} + login.UpsertUser = func(ctx *m.ReqContext, cmd *m.UpsertUserCommand) error { + cmd.User = &m.User{Id: 33} return nil - }) + } sc.fakeReq("GET", "/") sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") @@ -270,6 +276,11 @@ func TestMiddlewareContext(t *testing.T) { return nil }) + login.UpsertUser = func(ctx *m.ReqContext, cmd *m.UpsertUserCommand) error { + cmd.User = &m.User{Id: 33} + return nil + } + sc.fakeReq("GET", "/") sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") sc.req.RemoteAddr = "[2001::23]:12345"