Files
grafana/pkg/services/sqlstore/migrations/user_mig.go
Eric Leijonmarck 4fd3dd41bc ServiceAccounts: Delete ServiceAccount (#40470)
* 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

* registering as backend service

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>
2021-11-11 15:10:24 +00:00

172 lines
6.2 KiB
Go

package migrations
import (
"fmt"
. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/util"
"xorm.io/xorm"
)
func addUserMigrations(mg *Migrator) {
userV1 := Table{
Name: "user",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "version", Type: DB_Int, Nullable: false},
{Name: "login", Type: DB_NVarchar, Length: 190, Nullable: false},
{Name: "email", Type: DB_NVarchar, Length: 190, Nullable: false},
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true},
{Name: "rands", Type: DB_NVarchar, Length: 50, Nullable: true},
{Name: "company", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "account_id", Type: DB_BigInt, Nullable: false},
{Name: "is_admin", Type: DB_Bool, Nullable: false},
{Name: "created", Type: DB_DateTime, Nullable: false},
{Name: "updated", Type: DB_DateTime, Nullable: false},
},
Indices: []*Index{
{Cols: []string{"login"}, Type: UniqueIndex},
{Cols: []string{"email"}, Type: UniqueIndex},
},
}
// create table
mg.AddMigration("create user table", NewAddTableMigration(userV1))
// add indices
mg.AddMigration("add unique index user.login", NewAddIndexMigration(userV1, userV1.Indices[0]))
mg.AddMigration("add unique index user.email", NewAddIndexMigration(userV1, userV1.Indices[1]))
// ---------------------
// account -> org changes
//------- drop indexes ------------------
addDropAllIndicesMigrations(mg, "v1", userV1)
//------- rename table ------------------
addTableRenameMigration(mg, "user", "user_v1", "v1")
//------- recreate table with new column names ------------------
userV2 := Table{
Name: "user",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "version", Type: DB_Int, Nullable: false},
{Name: "login", Type: DB_NVarchar, Length: 190, Nullable: false},
{Name: "email", Type: DB_NVarchar, Length: 190, Nullable: false},
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true},
{Name: "rands", Type: DB_NVarchar, Length: 50, Nullable: true},
{Name: "company", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "org_id", Type: DB_BigInt, Nullable: false},
{Name: "is_admin", Type: DB_Bool, Nullable: false},
{Name: "email_verified", Type: DB_Bool, Nullable: true},
{Name: "theme", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "created", Type: DB_DateTime, Nullable: false},
{Name: "updated", Type: DB_DateTime, Nullable: false},
},
Indices: []*Index{
{Cols: []string{"login"}, Type: UniqueIndex},
{Cols: []string{"email"}, Type: UniqueIndex},
},
}
mg.AddMigration("create user table v2", NewAddTableMigration(userV2))
addTableIndicesMigrations(mg, "v2", userV2)
//------- copy data from v1 to v2 -------------------
mg.AddMigration("copy data_source v1 to v2", NewCopyTableDataMigration("user", "user_v1", map[string]string{
"id": "id",
"version": "version",
"login": "login",
"email": "email",
"name": "name",
"password": "password",
"salt": "salt",
"rands": "rands",
"company": "company",
"org_id": "account_id",
"is_admin": "is_admin",
"created": "created",
"updated": "updated",
}))
mg.AddMigration("Drop old table user_v1", NewDropTableMigration("user_v1"))
mg.AddMigration("Add column help_flags1 to user table", NewAddColumnMigration(userV2, &Column{
Name: "help_flags1", Type: DB_BigInt, Nullable: false, Default: "0",
}))
mg.AddMigration("Update user table charset", NewTableCharsetMigration("user", []*Column{
{Name: "login", Type: DB_NVarchar, Length: 190, Nullable: false},
{Name: "email", Type: DB_NVarchar, Length: 190, Nullable: false},
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true},
{Name: "rands", Type: DB_NVarchar, Length: 50, Nullable: true},
{Name: "company", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "theme", Type: DB_NVarchar, Length: 255, Nullable: true},
}))
mg.AddMigration("Add last_seen_at column to user", NewAddColumnMigration(userV2, &Column{
Name: "last_seen_at", Type: DB_DateTime, Nullable: true,
}))
// Adds salt & rands for old users who used ldap or oauth
mg.AddMigration("Add missing user data", &AddMissingUserSaltAndRandsMigration{})
// is_disabled indicates whether user disabled or not. Disabled user should not be able to log in.
// This field used in couple with LDAP auth to disable users removed from LDAP rather than delete it immediately.
mg.AddMigration("Add is_disabled column to user", NewAddColumnMigration(userV2, &Column{
Name: "is_disabled", Type: DB_Bool, Nullable: false, Default: "0",
}))
mg.AddMigration("Add index user.login/user.email", NewAddIndexMigration(userV2, &Index{
Cols: []string{"login", "email"},
}))
mg.AddMigration("Add is_service_account column to user", NewAddColumnMigration(userV2, &Column{
Name: "is_service_account", Type: DB_Bool, Nullable: false, Default: "0",
}))
}
type AddMissingUserSaltAndRandsMigration struct {
MigrationBase
}
func (m *AddMissingUserSaltAndRandsMigration) SQL(dialect Dialect) string {
return "code migration"
}
type TempUserDTO struct {
Id int64
Login string
}
func (m *AddMissingUserSaltAndRandsMigration) Exec(sess *xorm.Session, mg *Migrator) error {
users := make([]*TempUserDTO, 0)
err := sess.SQL(fmt.Sprintf("SELECT id, login from %s WHERE rands = ''", mg.Dialect.Quote("user"))).Find(&users)
if err != nil {
return err
}
for _, user := range users {
salt, err := util.GetRandomString(10)
if err != nil {
return err
}
rands, err := util.GetRandomString(10)
if err != nil {
return err
}
if _, err := sess.Exec("UPDATE "+mg.Dialect.Quote("user")+
" SET salt = ?, rands = ? WHERE id = ?", salt, rands, user.Id); err != nil {
return err
}
}
return nil
}