Serviceaccounts: Filtering service accounts from user queries (#41410)

* Add extra fields to OSS types to support enterprise

* WIP service accounts

* Update public/app/features/api-keys/ApiKeysForm.tsx

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>

* Create a service account at the same time as the API key

* Use service account credentials when accessing API with APIkey

* Throw better error

* Use Boolean for "create service account button"

* Add GetRole to service, merge RoleDTO and Role structs

This patch merges the identical OSS and Enterprise data structures, which improves the code for two reasons:

1.  Makes switching between OSS and Enterprise easier
2.  Reduces the chance of incompatibilities developing between the same functions in OSS and Enterprise

* Start work cloning permissions onto service account

* If API key is not linked to a service account, continue login as usual

* Fallback to old auth if no service account linked to key

* Commented

* Add CloneUserToServiceAccount

* Update mock.go

* Put graphical bits behind a feature toggle

* Start adding LinkAPIKeyToServiceAccount

* Update pkg/models/user.go

Co-authored-by: Eric Leijonmarck <eric.leijonmarck@gmail.com>

* Update pkg/api/apikey.go

Co-authored-by: Eric Leijonmarck <eric.leijonmarck@gmail.com>

* Update pkg/api/apikey.go

Co-authored-by: Eric Leijonmarck <eric.leijonmarck@gmail.com>

* Finish LinkAPIKeyToServiceAccount

* Update comment

* Handle api key link error

* Update pkg/services/sqlstore/apikey.go

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>

* Feature toggle

* Update pkg/services/accesscontrol/accesscontrol.go

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>

* Not needed (yet)

* Better error messages for OSS accesscontrol

* Set an invalid user id as default

* ServiceAccountId should be string

* Re-arrange field names

* ServiceAccountId is integer

* Update ossaccesscontrol.go

* Linter

* Remove fronend edits

* Remove console log

* Update ApiKeysForm.tsx

* feat: add serviceaccount deletion

* feat: make sure we do not accidently delete serviceaccount

* feat: ServiceAccount Type

* refactor: userDeletions function

* refactor: serviceaccount deletions\

* refactor: error name and removed attribute for userDeletecommand

* refactor:: remove serviceaccount type for now

* WIP

* add mocked function

* Remove unnecessary db query, move to right place

* Update pkg/services/accesscontrol/mock/mock.go

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>

* Update pkg/services/accesscontrol/mock/mock.go

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>

* Update pkg/services/accesscontrol/mock/mock.go

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>

* Better error messages

* Better and correcter error messages

* add mocked function

* refactor: move function call, add error msg

* add IsServiceAccount and fix table

* add service accounts package

* WIP

* WIP

* working serviceaccountsapi registration

* WIP tests

* test

* test working

* test running for service

* moved the error out of the models package

* fixed own review

* linting errors

* Update pkg/services/serviceaccounts/database/database.go

Co-authored-by: Jeremy Price <Jeremy.price@grafana.com>

* tests running for api

* WIP

* WIP

* removed unused secrets background svc

* removed background svc for serviceaccount infavor or wire.go

* serviceaccounts manager tests

* wip

* Filtering service accounts from the user queries in frontend

* clean up

* Update pkg/services/sqlstore/org_test.go

* methods on same type should have same receiver

* _ unused variable and comment

* add additional join for results query

* remove unused code

* remove error fmt

* refactor: change to only have false

* no new variable to the left hand side

* refactor: create serviceaccount cmd

* dialect fix

Co-authored-by: Jeremy Price <jeremy.price@grafana.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
This commit is contained in:
Eric Leijonmarck 2021-11-23 23:06:40 +00:00 committed by GitHub
parent 3af36b7e23
commit 9c11040c3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 22 additions and 5 deletions

View File

@ -42,10 +42,10 @@ func ProvideServiceAccountsService(
return s, nil
}
func (s *ServiceAccountsService) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error {
if !s.cfg.FeatureToggles["service-accounts"] {
s.log.Debug(ServiceAccountFeatureToggleNotFound)
func (sa *ServiceAccountsService) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error {
if !sa.cfg.FeatureToggles["service-accounts"] {
sa.log.Debug(ServiceAccountFeatureToggleNotFound)
return nil
}
return s.store.DeleteServiceAccount(ctx, orgID, serviceAccountID)
return sa.store.DeleteServiceAccount(ctx, orgID, serviceAccountID)
}

View File

@ -141,11 +141,15 @@ func TestAccountDataAccess(t *testing.T) {
ac1cmd := models.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
ac2cmd := models.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true}
serviceaccountcmd := models.CreateUserCommand{Login: "serviceaccount", Email: "service@test.com", Name: "serviceaccount name", IsAdmin: true, IsServiceAccount: true}
ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd)
require.NoError(t, err)
ac2, err := sqlStore.CreateUser(context.Background(), ac2cmd)
require.NoError(t, err)
// user only used for making sure we filter out the service accounts
_, err = sqlStore.CreateUser(context.Background(), serviceaccountcmd)
require.NoError(t, err)
t.Run("Should be able to read user info projection", func(t *testing.T) {
query := models.GetUserProfileQuery{UserId: ac1.Id}

View File

@ -107,6 +107,10 @@ func (ss *SQLStore) GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQu
whereConditions = append(whereConditions, "org_user.org_id = ?")
whereParams = append(whereParams, query.OrgId)
// TODO: add to chore, for cleaning up after we have created
// service accounts table in the modelling
whereConditions = append(whereConditions, fmt.Sprintf("%s.is_service_account = false", x.Dialect().Quote("user")))
if query.Query != "" {
queryWithWildcards := "%" + query.Query + "%"
whereConditions = append(whereConditions, "(email "+dialect.LikeStr()+" ? OR name "+dialect.LikeStr()+" ? OR login "+dialect.LikeStr()+" ?)")
@ -157,6 +161,10 @@ func (ss *SQLStore) SearchOrgUsers(ctx context.Context, query *models.SearchOrgU
whereConditions = append(whereConditions, "org_user.org_id = ?")
whereParams = append(whereParams, query.OrgID)
// TODO: add to chore, for cleaning up after we have created
// service accounts table in the modelling
whereConditions = append(whereConditions, fmt.Sprintf("%s.is_service_account = false", x.Dialect().Quote("user")))
if query.Query != "" {
queryWithWildcards := "%" + query.Query + "%"
whereConditions = append(whereConditions, "(email "+dialect.LikeStr()+" ? OR name "+dialect.LikeStr()+" ? OR login "+dialect.LikeStr()+" ?)")
@ -189,7 +197,8 @@ func (ss *SQLStore) SearchOrgUsers(ctx context.Context, query *models.SearchOrgU
// get total count
orgUser := models.OrgUser{}
countSess := x.Table("org_user")
countSess := x.Table("org_user").
Join("INNER", x.Dialect().Quote("user"), fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user")))
if len(whereConditions) > 0 {
countSess.Where(strings.Join(whereConditions, " AND "), whereParams...)

View File

@ -609,6 +609,10 @@ func SearchUsers(ctx context.Context, query *models.SearchUsersQuery) error {
whereParams := make([]interface{}, 0)
sess := x.Table("user").Alias("u")
// TODO: add to chore, for cleaning up after we have created
// service accounts table in the modelling
whereConditions = append(whereConditions, "u.is_service_account = false")
// Join with only most recent auth module
joinCondition := `(
SELECT id from user_auth