func (mg *Migrator) exec(m Migration) error { if mg.LogLevel <= log.INFO { log.Info("Migrator: exec migration id: %v", m.Id()) } err := mg.inTransaction(func(sess *xorm.Session) error { condition := m.GetCondition() if condition != nil { sql, args := condition.Sql(mg.dialect) results, err := sess.Query(sql, args...) if err != nil || len(results) == 0 { log.Info("Migrator: skipping migration id: %v, condition not fulfilled", m.Id()) return sess.Rollback() } } _, err := sess.Exec(m.Sql(mg.dialect)) if err != nil { log.Error(3, "Migrator: exec FAILED migration id: %v, err: %v", m.Id(), err) return err } return nil }) if err != nil { return err } return nil }
func (a *ldapAuther) getGrafanaUserFor(ldapUser *ldapUserInfo) (*m.User, error) { // validate that the user has access // if there are no ldap group mappings access is true // otherwise a single group must match access := len(a.server.LdapGroups) == 0 for _, ldapGroup := range a.server.LdapGroups { if ldapUser.isMemberOf(ldapGroup.GroupDN) { access = true break } } if !access { log.Info("Ldap Auth: user %s does not belong in any of the specified ldap groups, ldapUser groups: %v", ldapUser.Username, ldapUser.MemberOf) return nil, ErrInvalidCredentials } // get user from grafana db userQuery := m.GetUserByLoginQuery{LoginOrEmail: ldapUser.Username} if err := bus.Dispatch(&userQuery); err != nil { if err == m.ErrUserNotFound { return a.createGrafanaUser(ldapUser) } else { return nil, err } } return userQuery.Result, nil }
func EnsureAdminUser() { statsQuery := m.GetSystemStatsQuery{} if err := bus.Dispatch(&statsQuery); err != nil { log.Fatal(3, "Could not determine if admin user exists: %v", err) return } if statsQuery.Result.UserCount > 0 { return } cmd := m.CreateUserCommand{} cmd.Login = setting.AdminUser cmd.Email = setting.AdminUser + "@localhost" cmd.Password = setting.AdminPassword cmd.IsAdmin = true if err := bus.Dispatch(&cmd); err != nil { log.Error(3, "Failed to create default admin user", err) return } log.Info("Created default admin user: %v", setting.AdminUser) }
func LogConfigurationInfo() { var text bytes.Buffer text.WriteString("Configuration Info\n") text.WriteString("Config files:\n") for i, file := range configFiles { text.WriteString(fmt.Sprintf(" [%d]: %s\n", i, file)) } if len(appliedCommandLineProperties) > 0 { text.WriteString("Command lines overrides:\n") for i, prop := range appliedCommandLineProperties { text.WriteString(fmt.Sprintf(" [%d]: %s\n", i, prop)) } } if len(appliedEnvOverrides) > 0 { text.WriteString("\tEnvironment variables used:\n") for i, prop := range appliedEnvOverrides { text.WriteString(fmt.Sprintf(" [%d]: %s\n", i, prop)) } } text.WriteString("Paths:\n") text.WriteString(fmt.Sprintf(" home: %s\n", HomePath)) text.WriteString(fmt.Sprintf(" data: %s\n", DataPath)) text.WriteString(fmt.Sprintf(" logs: %s\n", LogsPath)) log.Info(text.String()) }
func Logger() macaron.Handler { return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) { start := time.Now() rw := res.(macaron.ResponseWriter) c.Next() uname := c.GetCookie(setting.CookieUserName) if len(uname) == 0 { uname = "-" } content := fmt.Sprintf("Completed %s %s \"%s %s %s\" %v %s %d bytes in %dus", c.RemoteAddr(), uname, req.Method, req.URL.Path, req.Proto, rw.Status(), http.StatusText(rw.Status()), rw.Size(), time.Since(start)/time.Microsecond) switch rw.Status() { case 200, 304: content = fmt.Sprintf("%s", content) if !setting.RouterLogging { return } case 404: content = fmt.Sprintf("%s", content) case 500: content = fmt.Sprintf("%s", content) } log.Info(content) } }
func getEngine() (*xorm.Engine, error) { LoadConfig() cnnstr := "" switch DbCfg.Type { case "mysql": cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8", DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name) case "postgres": var host, port = "127.0.0.1", "5432" fields := strings.Split(DbCfg.Host, ":") if len(fields) > 0 && len(strings.TrimSpace(fields[0])) > 0 { host = fields[0] } if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 { port = fields[1] } cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s", DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode) case "sqlite3": if !filepath.IsAbs(DbCfg.Path) { DbCfg.Path = filepath.Join(setting.DataPath, DbCfg.Path) } os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm) cnnstr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc&_loc=Local" default: return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type) } log.Info("Database: %v", DbCfg.Type) return xorm.NewEngine(DbCfg.Type, cnnstr) }
func loadLdapConfig() { if !setting.LdapEnabled { return } log.Info("Login: Ldap enabled, reading config file: %s", setting.LdapConfigFile) _, err := toml.DecodeFile(setting.LdapConfigFile, &ldapCfg) if err != nil { log.Fatal(3, "Failed to load ldap config file: %s", err) } if len(ldapCfg.Servers) == 0 { log.Fatal(3, "ldap enabled but no ldap servers defined in config file: %s", setting.LdapConfigFile) } // set default org id for _, server := range ldapCfg.Servers { assertNotEmptyCfg(server.SearchFilter, "search_filter") assertNotEmptyCfg(server.SearchBaseDNs, "search_base_dns") for _, groupMap := range server.LdapGroups { if groupMap.OrgId == 0 { groupMap.OrgId = 1 } } } }
func (a *ldapAuther) initialBind(username, userPassword string) error { if a.server.BindPassword != "" || a.server.BindDN == "" { userPassword = a.server.BindPassword a.requireSecondBind = true } bindPath := a.server.BindDN if strings.Contains(bindPath, "%s") { bindPath = fmt.Sprintf(a.server.BindDN, username) } if err := a.conn.Bind(bindPath, userPassword); err != nil { if ldapCfg.VerboseLogging { log.Info("LDAP initial bind failed, %v", err) } if ldapErr, ok := err.(*ldap.Error); ok { if ldapErr.ResultCode == 49 { return ErrInvalidCredentials } } return err } return nil }
func NewJsonDashIndex(path string) *JsonDashIndex { log.Info("Creating json dashboard index for path: %v", path) index := JsonDashIndex{} index.path = path index.updateIndex() return &index }
func initRuntime() { err := setting.NewConfigContext(&setting.CommandLineArgs{ Config: *configFile, HomePath: *homePath, Args: flag.Args(), }) if err != nil { log.Fatal(3, err.Error()) } log.Info("Starting Grafana") log.Info("Version: %v, Commit: %v, Build date: %v", setting.BuildVersion, setting.BuildCommit, time.Unix(setting.BuildStamp, 0)) setting.LogConfigurationInfo() sqlstore.NewEngine() sqlstore.EnsureAdminUser() }
func (a *ldapAuther) syncUserInfo(user *m.User, ldapUser *ldapUserInfo) error { var name = fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName) if user.Email == ldapUser.Email && user.Name == name { return nil } log.Info("Ldap: Syncing user info %s", ldapUser.Username) updateCmd := m.UpdateUserCommand{} updateCmd.UserId = user.Id updateCmd.Login = user.Login updateCmd.Email = ldapUser.Email updateCmd.Name = fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName) return bus.Dispatch(&updateCmd) }
func listenToSystemSignels() { signalChan := make(chan os.Signal, 1) code := 0 signal.Notify(signalChan, os.Interrupt) signal.Notify(signalChan, os.Kill) signal.Notify(signalChan, syscall.SIGTERM) select { case sig := <-signalChan: log.Info("Received signal %s. shutting down", sig) case code = <-exitChan: switch code { case 0: log.Info("Shutting down") default: log.Warn("Shutting down") } } log.Close() os.Exit(code) }
func (a *ldapAuther) secondBind(ldapUser *ldapUserInfo, userPassword string) error { if err := a.conn.Bind(ldapUser.DN, userPassword); err != nil { if ldapCfg.VerboseLogging { log.Info("LDAP second bind failed, %v", err) } if ldapErr, ok := err.(*ldap.Error); ok { if ldapErr.ResultCode == 49 { return ErrInvalidCredentials } } return err } return nil }
func (mg *Migrator) Start() error { if mg.LogLevel <= log.INFO { log.Info("Migrator: Starting DB migration") } logMap, err := mg.GetMigrationLog() if err != nil { return err } for _, m := range mg.migrations { _, exists := logMap[m.Id()] if exists { if mg.LogLevel <= log.DEBUG { log.Debug("Migrator: Skipping migration: %v, Already executed", m.Id()) } continue } sql := m.Sql(mg.dialect) record := MigrationLog{ MigrationId: m.Id(), Sql: sql, Timestamp: time.Now(), } if mg.LogLevel <= log.DEBUG { log.Debug("Migrator: Executing SQL: \n %v \n", sql) } if err := mg.exec(m); err != nil { log.Error(3, "Migrator: error: \n%s:\n%s", err, sql) record.Error = err.Error() mg.x.Insert(&record) return err } else { record.Success = true mg.x.Insert(&record) } } return nil }
func RenderToPng(params *RenderOpts) (string, error) { log.Info("PhantomRenderer::renderToPng url %v", params.Url) binPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, "phantomjs")) scriptPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, "render.js")) pngPath, _ := filepath.Abs(filepath.Join(setting.ImagesDir, util.GetRandomString(20))) pngPath = pngPath + ".png" cmd := exec.Command(binPath, "--ignore-ssl-errors=true", "--ssl-protocol=any", scriptPath, "url="+params.Url, "width="+params.Width, "height="+params.Height, "png="+pngPath, "cookiename="+setting.SessionOptions.CookieName, "domain="+setting.Domain, "sessionid="+params.SessionId) stdout, err := cmd.StdoutPipe() if err != nil { return "", err } stderr, err := cmd.StderrPipe() if err != nil { return "", err } err = cmd.Start() if err != nil { return "", err } go io.Copy(os.Stdout, stdout) go io.Copy(os.Stdout, stderr) done := make(chan error) go func() { cmd.Wait() close(done) }() select { case <-time.After(15 * time.Second): if err := cmd.Process.Kill(); err != nil { log.Error(4, "failed to kill: %v", err) } case <-done: } return pngPath, nil }
func (a *ldapAuther) login(query *LoginUserQuery) error { if err := a.Dial(); err != nil { return err } defer a.conn.Close() // perform initial authentication if err := a.initialBind(query.Username, query.Password); err != nil { return err } // find user entry & attributes if ldapUser, err := a.searchForUser(query.Username); err != nil { return err } else { if ldapCfg.VerboseLogging { log.Info("Ldap User Info: %s", spew.Sdump(ldapUser)) } // check if a second user bind is needed if a.requireSecondBind { if err := a.secondBind(ldapUser, query.Password); err != nil { return err } } if grafanaUser, err := a.getGrafanaUserFor(ldapUser); err != nil { return err } else { // sync user details if err := a.syncUserInfo(grafanaUser, ldapUser); err != nil { return err } // sync org roles if err := a.syncOrgRoles(grafanaUser, ldapUser); err != nil { return err } query.User = grafanaUser return nil } } }
func signUpStartedHandler(evt *events.SignUpStarted) error { if !setting.VerifyEmailEnabled { return nil } log.Info("User signup started: %s", evt.Email) if evt.Email == "" { return nil } return sendEmailCommandHandler(&m.SendEmailCommand{ To: []string{evt.Email}, Template: tmplSignUpStarted, Data: map[string]interface{}{ "Email": evt.Email, "Code": evt.Code, "SignUpUrl": setting.ToAbsUrl(fmt.Sprintf("signup/?email=%s&code=%s", url.QueryEscape(evt.Email), url.QueryEscape(evt.Code))), }, }) }
func StartServer() { var err error m := newMacaron() api.Register(m) listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort) log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl) switch setting.Protocol { case setting.HTTP: err = http.ListenAndServe(listenAddr, m) case setting.HTTPS: err = http.ListenAndServeTLS(listenAddr, setting.CertFile, setting.KeyFile, m) default: log.Fatal(4, "Invalid protocol: %s", setting.Protocol) } if err != nil { log.Fatal(4, "Fail to start server: %v", err) } }
func OAuthLogin(ctx *middleware.Context) { if setting.OAuthService == nil { ctx.Handle(404, "login.OAuthLogin(oauth service not enabled)", nil) return } name := ctx.Params(":name") connect, ok := social.SocialMap[name] if !ok { ctx.Handle(404, "login.OAuthLogin(social login not enabled)", errors.New(name)) return } code := ctx.Query("code") if code == "" { ctx.Redirect(connect.AuthCodeURL("", oauth2.AccessTypeOnline)) return } // handle call back token, err := connect.Exchange(oauth2.NoContext, code) if err != nil { ctx.Handle(500, "login.OAuthLogin(NewTransportWithCode)", err) return } log.Trace("login.OAuthLogin(Got token)") userInfo, err := connect.UserInfo(token) if err != nil { if err == social.ErrMissingTeamMembership { ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github team membership not fulfilled")) } else if err == social.ErrMissingOrganizationMembership { ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github organization membership not fulfilled")) } else { ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) } return } log.Trace("login.OAuthLogin(social login): %s", userInfo) // validate that the email is allowed to login to grafana if !connect.IsEmailAllowed(userInfo.Email) { log.Info("OAuth login attempt with unallowed email, %s", userInfo.Email) ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required email domain not fulfilled")) return } userQuery := m.GetUserByLoginQuery{LoginOrEmail: userInfo.Email} err = bus.Dispatch(&userQuery) // create account if missing if err == m.ErrUserNotFound { if !connect.IsSignupAllowed() { ctx.Redirect(setting.AppSubUrl + "/login") return } limitReached, err := middleware.QuotaReached(ctx, "user") if err != nil { ctx.Handle(500, "Failed to get user quota", err) return } if limitReached { ctx.Redirect(setting.AppSubUrl + "/login") return } cmd := m.CreateUserCommand{ Login: userInfo.Email, Email: userInfo.Email, Name: userInfo.Name, Company: userInfo.Company, } if err = bus.Dispatch(&cmd); err != nil { ctx.Handle(500, "Failed to create account", err) return } userQuery.Result = &cmd.Result } else if err != nil { ctx.Handle(500, "Unexpected error", err) } // login loginUserWithUser(userQuery.Result, ctx) metrics.M_Api_Login_OAuth.Inc(1) ctx.Redirect(setting.AppSubUrl + "/") }
func (a *ldapAuther) searchForUser(username string) (*ldapUserInfo, error) { var searchResult *ldap.SearchResult var err error for _, searchBase := range a.server.SearchBaseDNs { searchReq := ldap.SearchRequest{ BaseDN: searchBase, Scope: ldap.ScopeWholeSubtree, DerefAliases: ldap.NeverDerefAliases, Attributes: []string{ a.server.Attr.Username, a.server.Attr.Surname, a.server.Attr.Email, a.server.Attr.Name, a.server.Attr.MemberOf, }, Filter: strings.Replace(a.server.SearchFilter, "%s", username, -1), } searchResult, err = a.conn.Search(&searchReq) if err != nil { return nil, err } if len(searchResult.Entries) > 0 { break } } if len(searchResult.Entries) == 0 { return nil, ErrInvalidCredentials } if len(searchResult.Entries) > 1 { return nil, errors.New("Ldap search matched more than one entry, please review your filter setting") } var memberOf []string if a.server.GroupSearchFilter == "" { memberOf = getLdapAttrArray(a.server.Attr.MemberOf, searchResult) } else { // If we are using a POSIX LDAP schema it won't support memberOf, so we manually search the groups var groupSearchResult *ldap.SearchResult for _, groupSearchBase := range a.server.GroupSearchBaseDNs { filter := strings.Replace(a.server.GroupSearchFilter, "%s", username, -1) if ldapCfg.VerboseLogging { log.Info("LDAP: Searching for user's groups: %s", filter) } groupSearchReq := ldap.SearchRequest{ BaseDN: groupSearchBase, Scope: ldap.ScopeWholeSubtree, DerefAliases: ldap.NeverDerefAliases, Attributes: []string{ // Here MemberOf would be the thing that identifies the group, which is normally 'cn' a.server.Attr.MemberOf, }, Filter: filter, } groupSearchResult, err = a.conn.Search(&groupSearchReq) if err != nil { return nil, err } if len(groupSearchResult.Entries) > 0 { for i := range groupSearchResult.Entries { memberOf = append(memberOf, getLdapAttrN(a.server.Attr.MemberOf, groupSearchResult, i)) } break } } } return &ldapUserInfo{ DN: searchResult.Entries[0].DN, LastName: getLdapAttr(a.server.Attr.Surname, searchResult), FirstName: getLdapAttr(a.server.Attr.Name, searchResult), Username: getLdapAttr(a.server.Attr.Username, searchResult), Email: getLdapAttr(a.server.Attr.Email, searchResult), MemberOf: memberOf, }, nil }