Admin: Adds setting to disable creating initial admin user (#19505)

Adds a new setting disable_admin_user and when true the default 
admin user will not be created when Grafana starts for the first 
time (or no users exists in the system).

Closes #19038
This commit is contained in:
Shavonn Brown 2019-11-08 05:11:03 -05:00 committed by Marcus Efraimsson
parent 7ebc4a1568
commit 3e5abe7c21
7 changed files with 110 additions and 67 deletions

View File

@ -155,6 +155,9 @@ google_tag_manager_id =
#################################### Security ############################
[security]
# disable creation of admin user on first start of grafana
disable_initial_admin_creation = false
# default admin user, created on startup
admin_user = admin

View File

@ -151,6 +151,9 @@
#################################### Security ####################################
[security]
# disable creation of admin user on first start of grafana
;disable_initial_admin_creation = false
# default admin user, created on startup
;admin_user = admin

View File

@ -305,6 +305,12 @@ Example connstr: `127.0.0.1:11211`
## [security]
### disable_initial_admin_creation
> Only available in Grafana v6.5+.
Disable creation of admin user on first start of grafana.
### admin_user
The name of the default Grafana admin user (who has full permissions).

View File

@ -1,13 +1,18 @@
package sqlstore
import (
"context"
"fmt"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/events"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
const mainOrgName = "Main Org."
func init() {
bus.AddHandler("sql", GetOrgById)
bus.AddHandler("sql", CreateOrg)
@ -214,3 +219,60 @@ func DeleteOrg(cmd *m.DeleteOrgCommand) error {
return nil
})
}
func getOrCreateOrg(sess *DBSession, orgName string) (int64, error) {
var org m.Org
if setting.AutoAssignOrg {
has, err := sess.Where("id=?", setting.AutoAssignOrgId).Get(&org)
if err != nil {
return 0, err
}
if has {
return org.Id, nil
}
if setting.AutoAssignOrgId == 1 {
org.Name = mainOrgName
org.Id = int64(setting.AutoAssignOrgId)
} else {
sqlog.Info("Could not create user: organization id %v does not exist",
setting.AutoAssignOrgId)
return 0, fmt.Errorf("Could not create user: organization id %v does not exist",
setting.AutoAssignOrgId)
}
} else {
org.Name = orgName
}
org.Created = time.Now()
org.Updated = time.Now()
if org.Id != 0 {
if _, err := sess.InsertId(&org); err != nil {
return 0, err
}
} else {
if _, err := sess.InsertOne(&org); err != nil {
return 0, err
}
}
sess.publishAfterCommit(&events.OrgCreated{
Timestamp: org.Created,
Id: org.Id,
Name: org.Name,
})
return org.Id, nil
}
func createDefaultOrg(ctx context.Context) error {
return inTransactionCtx(ctx, func(sess *DBSession) error {
_, err := getOrCreateOrg(sess, mainOrgName)
if err != nil {
return err
}
return nil
})
}

View File

@ -55,11 +55,11 @@ type SqlStore struct {
Bus bus.Bus `inject:""`
CacheService *localcache.CacheService `inject:""`
dbCfg DatabaseConfig
engine *xorm.Engine
log log.Logger
Dialect migrator.Dialect
skipEnsureAdmin bool
dbCfg DatabaseConfig
engine *xorm.Engine
log log.Logger
Dialect migrator.Dialect
skipEnsureDefaultOrgAndUser bool
}
func (ss *SqlStore) Init() error {
@ -100,19 +100,16 @@ func (ss *SqlStore) Init() error {
// Register handlers
ss.addUserQueryAndCommandHandlers()
// ensure admin user
if ss.skipEnsureAdmin {
if ss.skipEnsureDefaultOrgAndUser {
return nil
}
return ss.ensureAdminUser()
return ss.ensureMainOrgAndAdminUser()
}
func (ss *SqlStore) ensureAdminUser() error {
systemUserCountQuery := m.GetSystemUserCountStatsQuery{}
func (ss *SqlStore) ensureMainOrgAndAdminUser() error {
err := ss.InTransaction(context.Background(), func(ctx context.Context) error {
systemUserCountQuery := m.GetSystemUserCountStatsQuery{}
err := bus.DispatchCtx(ctx, &systemUserCountQuery)
if err != nil {
return fmt.Errorf("Could not determine if admin user exists: %v", err)
@ -122,18 +119,28 @@ func (ss *SqlStore) ensureAdminUser() error {
return nil
}
cmd := m.CreateUserCommand{}
cmd.Login = setting.AdminUser
cmd.Email = setting.AdminUser + "@localhost"
cmd.Password = setting.AdminPassword
cmd.IsAdmin = true
// ensure admin user
if !ss.Cfg.DisableInitAdminCreation {
cmd := m.CreateUserCommand{}
cmd.Login = setting.AdminUser
cmd.Email = setting.AdminUser + "@localhost"
cmd.Password = setting.AdminPassword
cmd.IsAdmin = true
if err := bus.DispatchCtx(ctx, &cmd); err != nil {
return fmt.Errorf("Failed to create admin user: %v", err)
if err := bus.DispatchCtx(ctx, &cmd); err != nil {
return fmt.Errorf("Failed to create admin user: %v", err)
}
ss.log.Info("Created default admin", "user", setting.AdminUser)
return nil
}
ss.log.Info("Created default admin", "user", setting.AdminUser)
// ensure default org if default admin user is disabled
if err := createDefaultOrg(ctx); err != nil {
return errutil.Wrap("Failed to create default organization", err)
}
ss.log.Info("Created default organization")
return nil
})
@ -305,9 +312,9 @@ type ITestDB interface {
func InitTestDB(t ITestDB) *SqlStore {
t.Helper()
sqlstore := &SqlStore{}
sqlstore.skipEnsureAdmin = true
sqlstore.Bus = bus.New()
sqlstore.CacheService = localcache.New(5*time.Minute, 10*time.Minute)
sqlstore.skipEnsureDefaultOrgAndUser = true
dbType := migrator.SQLITE

View File

@ -35,62 +35,22 @@ func (ss *SqlStore) addUserQueryAndCommandHandlers() {
bus.AddHandlerCtx("sql", CreateUser)
}
func getOrgIdForNewUser(cmd *models.CreateUserCommand, sess *DBSession) (int64, error) {
func getOrgIdForNewUser(sess *DBSession, cmd *models.CreateUserCommand) (int64, error) {
if cmd.SkipOrgSetup {
return -1, nil
}
var org models.Org
if setting.AutoAssignOrg {
has, err := sess.Where("id=?", setting.AutoAssignOrgId).Get(&org)
if err != nil {
return 0, err
}
if has {
return org.Id, nil
}
if setting.AutoAssignOrgId == 1 {
org.Name = "Main Org."
org.Id = int64(setting.AutoAssignOrgId)
} else {
sqlog.Info("Could not create user: organization id %v does not exist",
setting.AutoAssignOrgId)
return 0, fmt.Errorf("Could not create user: organization id %v does not exist",
setting.AutoAssignOrgId)
}
} else {
org.Name = cmd.OrgName
if len(org.Name) == 0 {
org.Name = util.StringsFallback2(cmd.Email, cmd.Login)
}
orgName := cmd.OrgName
if len(orgName) == 0 {
orgName = util.StringsFallback2(cmd.Email, cmd.Login)
}
org.Created = time.Now()
org.Updated = time.Now()
if org.Id != 0 {
if _, err := sess.InsertId(&org); err != nil {
return 0, err
}
} else {
if _, err := sess.InsertOne(&org); err != nil {
return 0, err
}
}
sess.publishAfterCommit(&events.OrgCreated{
Timestamp: org.Created,
Id: org.Id,
Name: org.Name,
})
return org.Id, nil
return getOrCreateOrg(sess, orgName)
}
func CreateUser(ctx context.Context, cmd *models.CreateUserCommand) error {
return inTransactionCtx(ctx, func(sess *DBSession) error {
orgId, err := getOrgIdForNewUser(cmd, sess)
orgId, err := getOrgIdForNewUser(sess, cmd)
if err != nil {
return err
}

View File

@ -243,6 +243,7 @@ type Cfg struct {
RendererLimitAlerting int
// Security
DisableInitAdminCreation bool
DisableBruteForceLoginProtection bool
CookieSecure bool
CookieSameSite http.SameSite
@ -763,6 +764,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
}
// admin
cfg.DisableInitAdminCreation = security.Key("disable_initial_admin_creation").MustBool(false)
AdminUser, err = valueAsString(security, "admin_user", "")
if err != nil {
return err