Blame SOURCES/016-fix-CVE-2022-31107.patch

2e7f84
From 41a9a27cf0767828f38a390bbe7cf43f613b882e Mon Sep 17 00:00:00 2001
3cd0d1
From: Andreas Gerstmayr <agerstmayr@redhat.com>
3cd0d1
Date: Fri, 15 Jul 2022 14:05:14 +0200
3cd0d1
Subject: [PATCH] fix CVE-2022-31107
3cd0d1
3cd0d1
backport 967e17d7ef6bc62a108add33ea699710f0e15870 from v8.4.10
3cd0d1
3cd0d1
Co-authored-by: Karl Persson <kalle.persson@grafana.com>
3cd0d1
Co-authored-by: Jguer <joao.guerreiro@grafana.com>
3cd0d1
3cd0d1
diff --git a/pkg/api/ldap_debug.go b/pkg/api/ldap_debug.go
3cd0d1
index 126e760b67..c9e2b606c5 100644
3cd0d1
--- a/pkg/api/ldap_debug.go
3cd0d1
+++ b/pkg/api/ldap_debug.go
3cd0d1
@@ -215,6 +215,11 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) response.Respon
3cd0d1
 		ReqContext:    c,
3cd0d1
 		ExternalUser:  user,
3cd0d1
 		SignupAllowed: hs.Cfg.LDAPAllowSignup,
3cd0d1
+		UserLookupParams: models.UserLookupParams{
3cd0d1
+			UserID: &query.Result.Id, // Upsert by ID only
3cd0d1
+			Email:  nil,
3cd0d1
+			Login:  nil,
3cd0d1
+		},
3cd0d1
 	}
3cd0d1
 
3cd0d1
 	err = bus.Dispatch(upsertCmd)
3cd0d1
diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go
3cd0d1
index 1fce9b6f61..611d51444f 100644
3cd0d1
--- a/pkg/api/login_oauth.go
3cd0d1
+++ b/pkg/api/login_oauth.go
3cd0d1
@@ -250,6 +250,11 @@ func syncUser(
3cd0d1
 		ReqContext:    ctx,
3cd0d1
 		ExternalUser:  extUser,
3cd0d1
 		SignupAllowed: connect.IsSignupAllowed(),
3cd0d1
+		UserLookupParams: models.UserLookupParams{
3cd0d1
+			Email:  &extUser.Email,
3cd0d1
+			UserID: nil,
3cd0d1
+			Login:  nil,
3cd0d1
+		},
3cd0d1
 	}
3cd0d1
 	if err := bus.Dispatch(cmd); err != nil {
3cd0d1
 		return nil, err
3cd0d1
diff --git a/pkg/login/ldap_login.go b/pkg/login/ldap_login.go
3cd0d1
index cb5d984e73..82dac2ee9e 100644
3cd0d1
--- a/pkg/login/ldap_login.go
3cd0d1
+++ b/pkg/login/ldap_login.go
3cd0d1
@@ -56,9 +56,13 @@ var loginUsingLDAP = func(query *models.LoginUserQuery) (bool, error) {
3cd0d1
 		ReqContext:    query.ReqContext,
3cd0d1
 		ExternalUser:  externalUser,
3cd0d1
 		SignupAllowed: setting.LDAPAllowSignup,
3cd0d1
+		UserLookupParams: models.UserLookupParams{
3cd0d1
+			Login:  &externalUser.Login,
3cd0d1
+			Email:  &externalUser.Email,
3cd0d1
+			UserID: nil,
3cd0d1
+		},
3cd0d1
 	}
3cd0d1
-	err = bus.Dispatch(upsert)
3cd0d1
-	if err != nil {
3cd0d1
+	if err = bus.Dispatch(upsert); err != nil {
3cd0d1
 		return true, err
3cd0d1
 	}
3cd0d1
 	query.User = upsert.Result
3cd0d1
diff --git a/pkg/models/user_auth.go b/pkg/models/user_auth.go
3cd0d1
index 2061cf048b..a98efe659e 100644
3cd0d1
--- a/pkg/models/user_auth.go
3cd0d1
+++ b/pkg/models/user_auth.go
3cd0d1
@@ -54,11 +54,11 @@ type RequestURIKey struct{}
3cd0d1
 // COMMANDS
3cd0d1
 
3cd0d1
 type UpsertUserCommand struct {
3cd0d1
-	ReqContext    *ReqContext
3cd0d1
-	ExternalUser  *ExternalUserInfo
3cd0d1
+	ReqContext   *ReqContext
3cd0d1
+	ExternalUser *ExternalUserInfo
3cd0d1
+	UserLookupParams
3cd0d1
+	Result        *User
3cd0d1
 	SignupAllowed bool
3cd0d1
-
3cd0d1
-	Result *User
3cd0d1
 }
3cd0d1
 
3cd0d1
 type SetAuthInfoCommand struct {
3cd0d1
@@ -95,13 +95,18 @@ type LoginUserQuery struct {
3cd0d1
 type GetUserByAuthInfoQuery struct {
3cd0d1
 	AuthModule string
3cd0d1
 	AuthId     string
3cd0d1
-	UserId     int64
3cd0d1
-	Email      string
3cd0d1
-	Login      string
3cd0d1
+	UserLookupParams
3cd0d1
 
3cd0d1
 	Result *User
3cd0d1
 }
3cd0d1
 
3cd0d1
+type UserLookupParams struct {
3cd0d1
+	// Describes lookup order as well
3cd0d1
+	UserID *int64  // if set, will try to find the user by id
3cd0d1
+	Email  *string // if set, will try to find the user by email
3cd0d1
+	Login  *string // if set, will try to find the user by login
3cd0d1
+}
3cd0d1
+
3cd0d1
 type GetExternalUserInfoByLoginQuery struct {
3cd0d1
 	LoginOrEmail string
3cd0d1
 
3cd0d1
diff --git a/pkg/services/contexthandler/authproxy/authproxy.go b/pkg/services/contexthandler/authproxy/authproxy.go
3cd0d1
index 80e5a5b9e0..0d834748a7 100644
3cd0d1
--- a/pkg/services/contexthandler/authproxy/authproxy.go
3cd0d1
+++ b/pkg/services/contexthandler/authproxy/authproxy.go
3cd0d1
@@ -246,6 +246,11 @@ func (auth *AuthProxy) LoginViaLDAP() (int64, error) {
3cd0d1
 		ReqContext:    auth.ctx,
3cd0d1
 		SignupAllowed: auth.cfg.LDAPAllowSignup,
3cd0d1
 		ExternalUser:  extUser,
3cd0d1
+		UserLookupParams: models.UserLookupParams{
3cd0d1
+			Login:  &extUser.Login,
3cd0d1
+			Email:  &extUser.Email,
3cd0d1
+			UserID: nil,
3cd0d1
+		},
3cd0d1
 	}
3cd0d1
 	if err := bus.Dispatch(upsert); err != nil {
3cd0d1
 		return 0, err
3cd0d1
@@ -288,6 +293,11 @@ func (auth *AuthProxy) LoginViaHeader() (int64, error) {
3cd0d1
 		ReqContext:    auth.ctx,
3cd0d1
 		SignupAllowed: auth.cfg.AuthProxyAutoSignUp,
3cd0d1
 		ExternalUser:  extUser,
3cd0d1
+		UserLookupParams: models.UserLookupParams{
3cd0d1
+			UserID: nil,
3cd0d1
+			Login:  &extUser.Login,
3cd0d1
+			Email:  &extUser.Email,
3cd0d1
+		},
3cd0d1
 	}
3cd0d1
 
3cd0d1
 	err := bus.Dispatch(upsert)
3cd0d1
diff --git a/pkg/services/login/login.go b/pkg/services/login/login.go
3cd0d1
index 9e08a36b06..b74d1d3e8f 100644
3cd0d1
--- a/pkg/services/login/login.go
3cd0d1
+++ b/pkg/services/login/login.go
3cd0d1
@@ -37,11 +37,9 @@ func (ls *LoginService) UpsertUser(cmd *models.UpsertUserCommand) error {
3cd0d1
 	extUser := cmd.ExternalUser
3cd0d1
 
3cd0d1
 	userQuery := &models.GetUserByAuthInfoQuery{
3cd0d1
-		AuthModule: extUser.AuthModule,
3cd0d1
-		AuthId:     extUser.AuthId,
3cd0d1
-		UserId:     extUser.UserId,
3cd0d1
-		Email:      extUser.Email,
3cd0d1
-		Login:      extUser.Login,
3cd0d1
+		AuthModule:       extUser.AuthModule,
3cd0d1
+		AuthId:           extUser.AuthId,
3cd0d1
+		UserLookupParams: cmd.UserLookupParams,
3cd0d1
 	}
3cd0d1
 	if err := bus.Dispatch(userQuery); err != nil {
3cd0d1
 		if !errors.Is(err, models.ErrUserNotFound) {
3cd0d1
diff --git a/pkg/services/login/login_test.go b/pkg/services/login/login_test.go
3cd0d1
index 04953b567a..dd84ee29c8 100644
3cd0d1
--- a/pkg/services/login/login_test.go
3cd0d1
+++ b/pkg/services/login/login_test.go
3cd0d1
@@ -82,10 +82,12 @@ func Test_teamSync(t *testing.T) {
3cd0d1
 		QuotaService: &quota.QuotaService{},
3cd0d1
 	}
3cd0d1
 
3cd0d1
-	upserCmd := &models.UpsertUserCommand{ExternalUser: &models.ExternalUserInfo{Email: "test_user@example.org"}}
3cd0d1
+	email := "test_user@example.org"
3cd0d1
+	upserCmd := &models.UpsertUserCommand{ExternalUser: &models.ExternalUserInfo{Email: email},
3cd0d1
+		UserLookupParams: models.UserLookupParams{Email: &email}}
3cd0d1
 	expectedUser := &models.User{
3cd0d1
 		Id:    1,
3cd0d1
-		Email: "test_user@example.org",
3cd0d1
+		Email: email,
3cd0d1
 		Name:  "test_user",
3cd0d1
 		Login: "test_user",
3cd0d1
 	}
3cd0d1
diff --git a/pkg/services/sqlstore/user_auth.go b/pkg/services/sqlstore/user_auth.go
2e7f84
index 9605ccce76..f6f0e510bc 100644
3cd0d1
--- a/pkg/services/sqlstore/user_auth.go
3cd0d1
+++ b/pkg/services/sqlstore/user_auth.go
3cd0d1
@@ -40,11 +40,12 @@ func GetUserByAuthInfo(query *models.GetUserByAuthInfoQuery) error {
3cd0d1
 			}
3cd0d1
 
3cd0d1
 			// if user id was specified and doesn't match the user_auth entry, remove it
3cd0d1
-			if query.UserId != 0 && query.UserId != authQuery.Result.UserId {
3cd0d1
-				err = DeleteAuthInfo(&models.DeleteAuthInfoCommand{
3cd0d1
+			if query.UserLookupParams.UserID != nil &&
3cd0d1
+				*query.UserLookupParams.UserID != 0 &&
3cd0d1
+				*query.UserLookupParams.UserID != authQuery.Result.UserId {
3cd0d1
+				if err := DeleteAuthInfo(&models.DeleteAuthInfoCommand{
3cd0d1
 					UserAuth: authQuery.Result,
3cd0d1
-				})
3cd0d1
-				if err != nil {
3cd0d1
+				}); err != nil {
3cd0d1
 					sqlog.Error("Error removing user_auth entry", "error", err)
3cd0d1
 				}
3cd0d1
 
3cd0d1
@@ -70,17 +71,18 @@ func GetUserByAuthInfo(query *models.GetUserByAuthInfoQuery) error {
3cd0d1
 		}
3cd0d1
 	}
3cd0d1
 
3cd0d1
+	params := query.UserLookupParams
3cd0d1
 	// If not found, try to find the user by id
3cd0d1
-	if !has && query.UserId != 0 {
3cd0d1
-		has, err = x.Id(query.UserId).Get(user)
3cd0d1
+	if !has && params.UserID != nil && *params.UserID != 0 {
3cd0d1
+		has, err = x.Id(*params.UserID).Get(user)
3cd0d1
 		if err != nil {
3cd0d1
 			return err
3cd0d1
 		}
3cd0d1
 	}
3cd0d1
 
3cd0d1
 	// If not found, try to find the user by email address
3cd0d1
-	if !has && query.Email != "" {
3cd0d1
-		user = &models.User{Email: query.Email}
3cd0d1
+	if !has && params.Email != nil && *params.Email != "" {
3cd0d1
+		user = &models.User{Email: *params.Email}
3cd0d1
 		has, err = x.Get(user)
3cd0d1
 		if err != nil {
3cd0d1
 			return err
3cd0d1
@@ -88,8 +90,8 @@ func GetUserByAuthInfo(query *models.GetUserByAuthInfoQuery) error {
3cd0d1
 	}
3cd0d1
 
3cd0d1
 	// If not found, try to find the user by login
3cd0d1
-	if !has && query.Login != "" {
3cd0d1
-		user = &models.User{Login: query.Login}
3cd0d1
+	if !has && params.Login != nil && *params.Login != "" {
3cd0d1
+		user = &models.User{Login: *params.Login}
3cd0d1
 		has, err = x.Get(user)
3cd0d1
 		if err != nil {
3cd0d1
 			return err
3cd0d1
diff --git a/pkg/services/sqlstore/user_auth_test.go b/pkg/services/sqlstore/user_auth_test.go
3cd0d1
index e5bb2379e5..d94ce34edb 100644
3cd0d1
--- a/pkg/services/sqlstore/user_auth_test.go
3cd0d1
+++ b/pkg/services/sqlstore/user_auth_test.go
3cd0d1
@@ -45,7 +45,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			// By Login
3cd0d1
 			login := "loginuser0"
3cd0d1
 
3cd0d1
-			query := &models.GetUserByAuthInfoQuery{Login: login}
3cd0d1
+			query := &models.GetUserByAuthInfoQuery{UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 
3cd0d1
 			So(err, ShouldBeNil)
3cd0d1
@@ -54,7 +54,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			// By ID
3cd0d1
 			id := query.Result.Id
3cd0d1
 
3cd0d1
-			query = &models.GetUserByAuthInfoQuery{UserId: id}
3cd0d1
+			query = &models.GetUserByAuthInfoQuery{UserLookupParams: models.UserLookupParams{UserID: &id}}
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 
3cd0d1
 			So(err, ShouldBeNil)
3cd0d1
@@ -63,7 +63,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			// By Email
3cd0d1
 			email := "user1@test.com"
3cd0d1
 
3cd0d1
-			query = &models.GetUserByAuthInfoQuery{Email: email}
3cd0d1
+			query = &models.GetUserByAuthInfoQuery{UserLookupParams: models.UserLookupParams{Email: &email}}
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 
3cd0d1
 			So(err, ShouldBeNil)
3cd0d1
@@ -72,7 +72,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			// Don't find nonexistent user
3cd0d1
 			email = "nonexistent@test.com"
3cd0d1
 
3cd0d1
-			query = &models.GetUserByAuthInfoQuery{Email: email}
3cd0d1
+			query = &models.GetUserByAuthInfoQuery{UserLookupParams: models.UserLookupParams{Email: &email}}
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 
3cd0d1
 			So(err, ShouldEqual, models.ErrUserNotFound)
3cd0d1
@@ -90,7 +90,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			// create user_auth entry
3cd0d1
 			login := "loginuser0"
3cd0d1
 
3cd0d1
-			query.Login = login
3cd0d1
+			query.UserLookupParams.Login = &login
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 
3cd0d1
 			So(err, ShouldBeNil)
3cd0d1
@@ -104,9 +104,9 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			So(query.Result.Login, ShouldEqual, login)
3cd0d1
 
3cd0d1
 			// get with non-matching id
3cd0d1
-			id := query.Result.Id
3cd0d1
+			idPlusOne := query.Result.Id + 1
3cd0d1
 
3cd0d1
-			query.UserId = id + 1
3cd0d1
+			query.UserLookupParams.UserID = &idPlusOne
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 
3cd0d1
 			So(err, ShouldBeNil)
3cd0d1
@@ -143,7 +143,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			login := "loginuser0"
3cd0d1
 
3cd0d1
 			// Calling GetUserByAuthInfoQuery on an existing user will populate an entry in the user_auth table
3cd0d1
-			query := &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "test", AuthId: "test"}
3cd0d1
+			query := &models.GetUserByAuthInfoQuery{AuthModule: "test", AuthId: "test", UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 
3cd0d1
 			So(err, ShouldBeNil)
3cd0d1
@@ -178,7 +178,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			// Calling GetUserByAuthInfoQuery on an existing user will populate an entry in the user_auth table
3cd0d1
 			// Make the first log-in during the past
3cd0d1
 			getTime = func() time.Time { return time.Now().AddDate(0, 0, -2) }
3cd0d1
-			query := &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "test1", AuthId: "test1"}
3cd0d1
+			query := &models.GetUserByAuthInfoQuery{AuthModule: "test1", AuthId: "test1", UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 			getTime = time.Now
3cd0d1
 
3cd0d1
@@ -188,7 +188,7 @@ func TestUserAuth(t *testing.T) {
3cd0d1
 			// Add a second auth module for this user
3cd0d1
 			// Have this module's last log-in be more recent
3cd0d1
 			getTime = func() time.Time { return time.Now().AddDate(0, 0, -1) }
3cd0d1
-			query = &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "test2", AuthId: "test2"}
3cd0d1
+			query = &models.GetUserByAuthInfoQuery{AuthModule: "test2", AuthId: "test2", UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 			err = GetUserByAuthInfo(query)
3cd0d1
 			getTime = time.Now
3cd0d1
 
3cd0d1
diff --git a/pkg/services/sqlstore/user_test.go b/pkg/services/sqlstore/user_test.go
3cd0d1
index 7da19f0ef4..aa796ffb02 100644
3cd0d1
--- a/pkg/services/sqlstore/user_test.go
3cd0d1
+++ b/pkg/services/sqlstore/user_test.go
3cd0d1
@@ -455,7 +455,7 @@ func TestUserDataAccess(t *testing.T) {
3cd0d1
 				// Calling GetUserByAuthInfoQuery on an existing user will populate an entry in the user_auth table
3cd0d1
 				// Make the first log-in during the past
3cd0d1
 				getTime = func() time.Time { return time.Now().AddDate(0, 0, -2) }
3cd0d1
-				query := &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "ldap", AuthId: "ldap0"}
3cd0d1
+				query := &models.GetUserByAuthInfoQuery{AuthModule: "ldap", AuthId: "ldap0", UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 				err := GetUserByAuthInfo(query)
3cd0d1
 				getTime = time.Now
3cd0d1
 
3cd0d1
@@ -465,7 +465,7 @@ func TestUserDataAccess(t *testing.T) {
3cd0d1
 				// Add a second auth module for this user
3cd0d1
 				// Have this module's last log-in be more recent
3cd0d1
 				getTime = func() time.Time { return time.Now().AddDate(0, 0, -1) }
3cd0d1
-				query = &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "oauth", AuthId: "oauth0"}
3cd0d1
+				query = &models.GetUserByAuthInfoQuery{AuthModule: "oauth", AuthId: "oauth0", UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 				err = GetUserByAuthInfo(query)
3cd0d1
 				getTime = time.Now
3cd0d1
 
3cd0d1
@@ -511,7 +511,7 @@ func TestUserDataAccess(t *testing.T) {
3cd0d1
 					// Calling GetUserByAuthInfoQuery on an existing user will populate an entry in the user_auth table
3cd0d1
 					// Make the first log-in during the past
3cd0d1
 					getTime = func() time.Time { return time.Now().AddDate(0, 0, -2) }
3cd0d1
-					query := &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "ldap", AuthId: fmt.Sprint("ldap", i)}
3cd0d1
+					query := &models.GetUserByAuthInfoQuery{AuthModule: "ldap", AuthId: fmt.Sprint("ldap", i), UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 					err := GetUserByAuthInfo(query)
3cd0d1
 					getTime = time.Now
3cd0d1
 
3cd0d1
@@ -522,7 +522,7 @@ func TestUserDataAccess(t *testing.T) {
3cd0d1
 				// Log in first user with oauth
3cd0d1
 				login := "loginuser0"
3cd0d1
 				getTime = func() time.Time { return time.Now().AddDate(0, 0, -1) }
3cd0d1
-				query := &models.GetUserByAuthInfoQuery{Login: login, AuthModule: "oauth", AuthId: "oauth0"}
3cd0d1
+				query := &models.GetUserByAuthInfoQuery{AuthModule: "oauth", AuthId: "oauth0", UserLookupParams: models.UserLookupParams{Login: &login}}
3cd0d1
 				err := GetUserByAuthInfo(query)
3cd0d1
 				getTime = time.Now
3cd0d1