Commit fdfcc3ab by Torkel Ödegaard

Admin flagged users, create a default admin user on startup if missing

parent 5ec07db1
......@@ -35,6 +35,12 @@ session_id_hashfunc = sha1
; Session hash key, default is use random string
session_id_hashkey =
[admin]
; default admin user, created on startup
user = admin
; default admin password, can be changed before first start of grafana, or in profile settings
password = admin
[auth]
anonymous = false
anonymous_account_id =
......
Subproject commit 961ebbde6b6540f03d3fb5a1741722614166099f
Subproject commit cf344abff2cdf7638d1748aa698caf23c3848715
......@@ -16,6 +16,7 @@ type LoginResult struct {
type CurrentUser struct {
Login string `json:"login"`
Email string `json:"email"`
IsAdmin bool `json:"isAdmin"`
GravatarUrl string `json:"gravatarUrl"`
}
......@@ -48,6 +49,7 @@ func NewCurrentUser(account *models.Account) *CurrentUser {
model.Login = account.Login
model.Email = account.Email
model.GravatarUrl = getGravatarUrl(account.Email)
model.IsAdmin = account.IsAdmin
}
return model
}
......
......@@ -16,9 +16,9 @@ import (
"github.com/torkelo/grafana-pro/pkg/api"
"github.com/torkelo/grafana-pro/pkg/log"
"github.com/torkelo/grafana-pro/pkg/middleware"
"github.com/torkelo/grafana-pro/pkg/services/sqlstore"
"github.com/torkelo/grafana-pro/pkg/setting"
"github.com/torkelo/grafana-pro/pkg/social"
"github.com/torkelo/grafana-pro/pkg/stores/sqlstore"
)
var CmdWeb = cli.Command{
......@@ -76,11 +76,9 @@ func runWeb(c *cli.Context) {
log.Info("Version: %v, Commit: %v, Build date: %v", setting.BuildVersion, setting.BuildCommit, time.Unix(setting.BuildStamp, 0))
setting.NewConfigContext()
setting.InitServices()
social.NewOAuthService()
sqlstore.Init()
sqlstore.NewEngine()
sqlstore.EnsureAdminUser()
m := newMacaron()
api.Register(m)
......
......@@ -31,13 +31,15 @@ type Account struct {
// COMMANDS
type CreateAccountCommand struct {
Email string `json:"email" binding:"required"`
Login string `json:"login"`
Password string `json:"password" binding:"required"`
Name string `json:"name"`
Company string `json:"company"`
Salt string `json:"-"`
Result Account `json:"-"`
Email string `json:"email" binding:"required"`
Login string `json:"login"`
Password string `json:"password" binding:"required"`
Name string `json:"name"`
Company string `json:"company"`
Salt string `json:"-"`
IsAdmin bool `json:"-"`
Result Account `json:"-"`
}
type SetUsingAccountCommand struct {
......
package sqlstore
import (
"strings"
"time"
"github.com/go-xorm/xorm"
......@@ -30,10 +31,13 @@ func CreateAccount(cmd *m.CreateAccountCommand) error {
Login: cmd.Login,
Password: cmd.Password,
Salt: cmd.Salt,
IsAdmin: cmd.IsAdmin,
Created: time.Now(),
Updated: time.Now(),
}
sess.UseBool("is_admin")
_, err := sess.Insert(&account)
cmd.Result = account
return err
......@@ -137,10 +141,14 @@ func GetAccountByToken(query *m.GetAccountByTokenQuery) error {
}
func GetAccountByLogin(query *m.GetAccountByLoginQuery) error {
var err error
account := new(m.Account)
if strings.Contains(query.Login, "@") {
account = &m.Account{Email: query.Login}
} else {
account = &m.Account{Login: strings.ToLower(query.Login)}
}
account := m.Account{Login: query.Login}
has, err := x.Get(&account)
has, err := x.Get(account)
if err != nil {
return err
......@@ -152,7 +160,7 @@ func GetAccountByLogin(query *m.GetAccountByLoginQuery) error {
account.UsingAccountId = account.Id
}
query.Result = &account
query.Result = account
return nil
}
......
......@@ -6,9 +6,11 @@ import (
"path"
"strings"
"github.com/torkelo/grafana-pro/pkg/bus"
"github.com/torkelo/grafana-pro/pkg/log"
m "github.com/torkelo/grafana-pro/pkg/models"
"github.com/torkelo/grafana-pro/pkg/setting"
"github.com/torkelo/grafana-pro/pkg/util"
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/xorm"
......@@ -42,23 +44,39 @@ func init() {
new(m.Token))
}
func Init() {
func EnsureAdminUser() {
adminQuery := m.GetAccountByLoginQuery{Login: setting.AdminUser}
if err := bus.Dispatch(&adminQuery); err == m.ErrAccountNotFound {
cmd := m.CreateAccountCommand{}
cmd.Login = setting.AdminUser
cmd.Email = setting.AdminUser + "@localhost"
cmd.Salt = util.GetRandomString(10)
cmd.Password = util.EncodePassword(setting.AdminPassword, cmd.Salt)
cmd.IsAdmin = true
if err = bus.Dispatch(&cmd); err != nil {
log.Fatal(3, "Failed to create default admin user", err)
}
log.Info("Created default admin user: %v", setting.AdminUser)
} else if err != nil {
log.Fatal(3, "Could not determine if admin user exists: %v", err)
}
}
func NewEngine() (err error) {
x, err = getEngine()
func NewEngine() {
x, err := getEngine()
if err != nil {
return fmt.Errorf("sqlstore.init(fail to connect to database): %v", err)
log.Fatal(3, "Sqlstore: Fail to connect to database: %v", err)
}
err = SetEngine(x, true)
if err != nil {
log.Fatal(4, "fail to initialize orm engine: %v", err)
log.Fatal(3, "fail to initialize orm engine: %v", err)
}
return nil
}
func SetEngine(engine *xorm.Engine, enableLog bool) (err error) {
......
......@@ -59,6 +59,8 @@ var (
EnableGzip bool
// Http auth
AdminUser string
AdminPassword string
Anonymous bool
AnonymousAccountId int64
......@@ -119,7 +121,7 @@ func findConfigFiles() []string {
func NewConfigContext() {
configFiles := findConfigFiles()
log.Info("Loading config files: %v", configFiles)
//log.Info("Loading config files: %v", configFiles)
var err error
Cfg, err = goconfig.LoadConfigFile(configFiles[0])
......@@ -168,6 +170,8 @@ func NewConfigContext() {
EnableGzip = Cfg.MustBool("server", "enable_gzip")
// Http auth
AdminUser = Cfg.MustValue("admin", "user", "admin")
AdminPassword = Cfg.MustValue("admin", "password", "admin")
Anonymous = Cfg.MustBool("auth", "anonymous", false)
AnonymousAccountId = Cfg.MustInt64("auth", "anonymous_account_id", 0)
......@@ -180,10 +184,11 @@ func NewConfigContext() {
PhantomDir = "_vendor/phantomjs"
LogRootPath = Cfg.MustValue("log", "root_path", path.Join(WorkDir, "/data/log"))
}
func initSessionService() {
readSessionConfig()
}
func readSessionConfig() {
SessionOptions = session.Options{}
SessionOptions.Provider = Cfg.MustValueRange("session", "provider", "memory", []string{"memory", "file"})
SessionOptions.ProviderConfig = strings.Trim(Cfg.MustValue("session", "provider_config"), "\" ")
......@@ -199,7 +204,3 @@ func initSessionService() {
log.Info("Session Service Enabled")
}
func InitServices() {
initSessionService()
}
package stores
//
// import (
// "encoding/json"
// "io"
// "os"
// "path/filepath"
// "strings"
//
// log "github.com/alecthomas/log4go"
// "github.com/torkelo/grafana-pro/pkg/models"
// )
//
// type fileStore struct {
// dataDir string
// dashDir string
// cache map[string]*models.Dashboard
// }
//
// func NewFileStore(dataDir string) *fileStore {
//
// if dirDoesNotExist(dataDir) {
// log.Crashf("FileStore failed to initialize, dataDir does not exist %v", dataDir)
// }
//
// dashDir := filepath.Join(dataDir, "dashboards")
//
// if dirDoesNotExist(dashDir) {
// log.Debug("Did not find dashboard dir, creating...")
// err := os.Mkdir(dashDir, 0777)
// if err != nil {
// log.Crashf("FileStore failed to initialize, could not create directory %v, error: %v", dashDir, err)
// }
// }
//
// store := &fileStore{}
// store.dataDir = dataDir
// store.dashDir = dashDir
// store.cache = make(map[string]*models.Dashboard)
// store.scanFiles()
//
// return store
// }
//
// func (store *fileStore) scanFiles() {
// visitor := func(path string, f os.FileInfo, err error) error {
// if err != nil {
// return err
// }
// if f.IsDir() {
// return nil
// }
// if strings.HasSuffix(f.Name(), ".json") {
// err = store.loadDashboardIntoCache(path)
// if err != nil {
// return err
// }
// }
// return nil
// }
//
// err := filepath.Walk(store.dashDir, visitor)
// if err != nil {
// log.Error("FileStore::updateCache failed %v", err)
// }
// }
//
// func (store fileStore) loadDashboardIntoCache(filename string) error {
// log.Info("Loading dashboard file %v into cache", filename)
// dash, err := loadDashboardFromFile(filename)
// if err != nil {
// return err
// }
//
// store.cache[dash.Title] = dash
//
// return nil
// }
//
// func (store *fileStore) Close() {
//
// }
//
// func (store *fileStore) GetById(id string) (*models.Dashboard, error) {
// log.Debug("FileStore::GetById id = %v", id)
// filename := store.getFilePathForDashboard(id)
//
// return loadDashboardFromFile(filename)
// }
//
// func (store *fileStore) Save(dash *models.Dashboard) error {
// filename := store.getFilePathForDashboard(dash.Title)
//
// log.Debug("Saving dashboard %v to %v", dash.Title, filename)
//
// var err error
// var data []byte
// if data, err = json.Marshal(dash.Data); err != nil {
// return err
// }
//
// return writeFile(filename, data)
// }
//
// func (store *fileStore) Query(query string) ([]*models.SearchResult, error) {
// results := make([]*models.SearchResult, 0, 50)
//
// for _, dash := range store.cache {
// item := &models.SearchResult{
// Id: dash.Title,
// Type: "dashboard",
// }
// results = append(results, item)
// }
//
// return results, nil
// }
//
// func loadDashboardFromFile(filename string) (*models.Dashboard, error) {
// log.Debug("FileStore::loading dashboard from file %v", filename)
//
// configFile, err := os.Open(filename)
// if err != nil {
// return nil, err
// }
//
// return models.NewFromJson(configFile)
// }
//
// func (store *fileStore) getFilePathForDashboard(id string) string {
// id = strings.ToLower(id)
// id = strings.Replace(id, " ", "-", -1)
// return filepath.Join(store.dashDir, id) + ".json"
// }
//
// func dirDoesNotExist(dir string) bool {
// _, err := os.Stat(dir)
// return os.IsNotExist(err)
// }
//
// func writeFile(filename string, data []byte) error {
// f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
// if err != nil {
// return err
// }
// n, err := f.Write(data)
// if err == nil && n < len(data) {
// err = io.ErrShortWrite
// }
// if err1 := f.Close(); err == nil {
// err = err1
// }
//
// return err
// }
package stores
//
// import (
// "fmt"
// "io"
// "io/ioutil"
// "os"
// "path/filepath"
// "testing"
//
// . "github.com/smartystreets/goconvey/convey"
// "github.com/torkelo/grafana-pro/pkg/models"
// )
//
// func TestFileStore(t *testing.T) {
//
// GivenFileStore("When saving a dashboard", t, func(store *fileStore) {
// dashboard := models.NewDashboard("hello")
//
// err := store.Save(dashboard)
//
// Convey("should be saved to disk", func() {
// So(err, ShouldBeNil)
//
// _, err = os.Stat(store.getFilePathForDashboard("hello"))
// So(err, ShouldBeNil)
// })
// })
//
// GivenFileStore("When getting a saved dashboard", t, func(store *fileStore) {
// copyDashboardToTempData("default.json", "", store.dashDir)
// dash, err := store.GetById("default")
//
// Convey("should be read from disk", func() {
// So(err, ShouldBeNil)
// So(dash, ShouldNotBeNil)
//
// So(dash.Title, ShouldEqual, "Grafana Play Home")
// })
// })
//
// GivenFileStore("when getting dashboard with capital letters", t, func(store *fileStore) {
// copyDashboardToTempData("annotations.json", "", store.dashDir)
// dash, err := store.GetById("AnnoTations")
//
// Convey("should be read from disk", func() {
// So(err, ShouldBeNil)
// So(dash, ShouldNotBeNil)
//
// So(dash.Title, ShouldEqual, "Annotations")
// })
// })
//
// GivenFileStore("When copying dashboards into data dir", t, func(store *fileStore) {
// copyDashboardToTempData("annotations.json", "", store.dashDir)
// copyDashboardToTempData("default.json", "", store.dashDir)
// copyDashboardToTempData("graph-styles.json", "", store.dashDir)
// store.scanFiles()
//
// Convey("scan should generate index of all dashboards", func() {
//
// result, err := store.Query("*")
// So(err, ShouldBeNil)
// So(len(result), ShouldEqual, 3)
// })
// })
// }
//
// func copyDashboardToTempData(name string, destName string, dir string) {
// if destName == "" {
// destName = name
// }
// source, _ := filepath.Abs("../../data/dashboards/" + name)
// dest := filepath.Join(dir, destName)
// err := copyFile(dest, source)
// if err != nil {
// panic(fmt.Sprintf("failed to copy file %v", name))
// }
// }
//
// func GivenFileStore(desc string, t *testing.T, f func(store *fileStore)) {
// Convey(desc, t, func() {
// tempDir, _ := ioutil.TempDir("", "store")
//
// store := NewFileStore(tempDir)
//
// f(store)
//
// Reset(func() {
// os.RemoveAll(tempDir)
// })
// })
// }
//
// func copyFile(dst, src string) error {
// in, err := os.Open(src)
// if err != nil {
// return err
// }
// defer in.Close()
// out, err := os.Create(dst)
// if err != nil {
// return err
// }
// defer out.Close()
// _, err = io.Copy(out, in)
// cerr := out.Close()
// if err != nil {
// return err
// }
// return cerr
// }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment