func sendUsageStats() { log.Trace("Sending anonymous usage stats to stats.grafana.org") version := strings.Replace(setting.BuildVersion, ".", "_", -1) metrics := map[string]interface{}{} report := map[string]interface{}{ "version": version, "metrics": metrics, } UsageStats.Each(func(name string, i interface{}) { switch metric := i.(type) { case Counter: if metric.Count() > 0 { metrics[name+".count"] = metric.Count() metric.Clear() } } }) statsQuery := m.GetSystemStatsQuery{} if err := bus.Dispatch(&statsQuery); err != nil { log.Error(3, "Failed to get system stats", err) return } metrics["stats.dashboards.count"] = statsQuery.Result.DashboardCount metrics["stats.users.count"] = statsQuery.Result.UserCount metrics["stats.orgs.count"] = statsQuery.Result.OrgCount metrics["stats.playlist.count"] = statsQuery.Result.PlaylistCount metrics["stats.plugins.apps.count"] = len(plugins.Apps) metrics["stats.plugins.panels.count"] = len(plugins.Panels) metrics["stats.plugins.datasources.count"] = len(plugins.DataSources) dsStats := m.GetDataSourceStatsQuery{} if err := bus.Dispatch(&dsStats); err != nil { log.Error(3, "Failed to get datasource stats", err) return } // send counters for each data source // but ignore any custom data sources // as sending that name could be sensitive information dsOtherCount := 0 for _, dsStat := range dsStats.Result { if m.IsKnownDataSourcePlugin(dsStat.Type) { metrics["stats.ds."+dsStat.Type+".count"] = dsStat.Count } else { dsOtherCount += dsStat.Count } } metrics["stats.ds.other.count"] = dsOtherCount out, _ := json.MarshalIndent(report, "", " ") data := bytes.NewBuffer(out) client := http.Client{Timeout: time.Duration(5 * time.Second)} go client.Post("https://stats.grafana.org/grafana-usage-report", "application/json", data) }
func tryLoginUsingRememberCookie(c *middleware.Context) bool { // Check auto-login. uname := c.GetCookie(setting.CookieUserName) if len(uname) == 0 { return false } isSucceed := false defer func() { if !isSucceed { log.Trace("auto-login cookie cleared: %s", uname) c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/") c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/") return } }() userQuery := m.GetUserByLoginQuery{LoginOrEmail: uname} if err := bus.Dispatch(&userQuery); err != nil { return false } user := userQuery.Result // validate remember me cookie if val, _ := c.GetSuperSecureCookie( util.EncodeMd5(user.Rands+user.Password), setting.CookieRememberName); val != user.Login { return false } isSucceed = true loginUserWithUser(user, c) return true }
func getHeaders(route *plugins.AppPluginRoute, orgId int64, appId string) (http.Header, error) { result := http.Header{} query := m.GetAppSettingByAppIdQuery{OrgId: orgId, AppId: appId} if err := bus.Dispatch(&query); err != nil { return nil, err } data := templateData{ JsonData: query.Result.JsonData, SecureJsonData: query.Result.SecureJsonData.Decrypt(), } for _, header := range route.Headers { var contentBuf bytes.Buffer t, err := template.New("content").Parse(header.Content) if err != nil { return nil, errors.New(fmt.Sprintf("could not parse header content template for header %s.", header.Name)) } err = t.Execute(&contentBuf, data) if err != nil { return nil, errors.New(fmt.Sprintf("failed to execute header content template for header %s.", header.Name)) } log.Trace("Adding header to proxy request. %s: %s", header.Name, contentBuf.String()) result.Add(header.Name, contentBuf.String()) } return result, nil }
func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) { urlPath := r.URL.Path hash := urlPath[strings.LastIndex(urlPath, "/")+1:] var avatar *Avatar if avatar, _ = this.cache[hash]; avatar == nil { avatar = New(hash) } if avatar.Expired() { if err := avatar.Update(); err != nil { log.Trace("avatar update error: %v", err) } } if avatar.notFound { avatar = this.notFound } else { this.cache[hash] = avatar } w.Header().Set("Content-Type", "image/jpeg") w.Header().Set("Content-Length", strconv.Itoa(len(avatar.data.Bytes()))) w.Header().Set("Cache-Control", "private, max-age=3600") if err := avatar.Encode(w); err != nil { log.Warn("avatar encode error: %v", err) w.WriteHeader(500) } }
func AuthenticateUnscoped(data *Auth_data) error { log.Trace("AuthenticateUnscoped()") var auth_post auth_request_struct auth_post.Auth.Scope = "unscoped" auth_post.Auth.Identity.Methods = []string{"password"} auth_post.Auth.Identity.Password.User.Name = data.Username auth_post.Auth.Identity.Password.User.Password = data.Password auth_post.Auth.Identity.Password.User.Domain.Name = data.Domain b, _ := json.Marshal(auth_post) return authenticate(data, b) }
func (a *keystoneAuther) login(query *LoginUserQuery) error { log.Trace("perform initial authentication") // perform initial authentication if err := a.authenticate(query.Username, query.Password); err != nil { return err } log.Trace("Get grafana user") if grafanaUser, err := a.getGrafanaUserFor(query.Username); err != nil { return err } else { log.Trace("sync org roles") // sync org roles if err := a.syncOrgRoles(query.Username, query.Password, grafanaUser); err != nil { return err } query.User = grafanaUser return nil } }
func AuthenticateScoped(data *Auth_data) error { if data.UnscopedToken != "" { log.Trace("AuthenticateScoped() with token") var auth_post scoped_auth_token_request_struct auth_post.Auth.Identity.Methods = []string{"token"} auth_post.Auth.Identity.Token.Id = data.UnscopedToken auth_post.Auth.Scope.Project.Domain.Name = data.Domain auth_post.Auth.Scope.Project.Name = data.Project b, _ := json.Marshal(auth_post) return authenticate(data, b) } else { var auth_post scoped_auth_password_request_struct log.Trace("AuthenticateScoped() with password") auth_post.Auth.Identity.Methods = []string{"password"} auth_post.Auth.Identity.Password.User.Name = data.Username auth_post.Auth.Identity.Password.User.Password = data.Password auth_post.Auth.Identity.Password.User.Domain.Name = data.Domain auth_post.Auth.Scope.Project.Domain.Name = data.Domain auth_post.Auth.Scope.Project.Name = data.Project b, _ := json.Marshal(auth_post) return authenticate(data, b) } }
func processMailQueue() { for { select { case msg := <-mailQueue: num, err := buildAndSend(msg) tos := strings.Join(msg.To, "; ") info := "" if err != nil { if len(msg.Info) > 0 { info = ", info: " + msg.Info } log.Error(4, fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err)) } else { log.Trace(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info)) } } } }
func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins.AppPluginRoute, appId string) *httputil.ReverseProxy { targetUrl, _ := url.Parse(route.Url) director := func(req *http.Request) { req.URL.Scheme = targetUrl.Scheme req.URL.Host = targetUrl.Host req.Host = targetUrl.Host req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath) // clear cookie headers req.Header.Del("Cookie") req.Header.Del("Set-Cookie") //Create a HTTP header with the context in it. ctxJson, err := json.Marshal(ctx.SignedInUser) if err != nil { ctx.JsonApiErr(500, "failed to marshal context to json.", err) return } req.Header.Add("X-Grafana-Context", string(ctxJson)) if len(route.Headers) > 0 { headers, err := getHeaders(route, ctx.OrgId, appId) if err != nil { ctx.JsonApiErr(500, "Could not generate plugin route header", err) return } for key, value := range headers { log.Trace("setting key %v value %v", key, value[0]) req.Header.Set(key, value[0]) } } } return &httputil.ReverseProxy{Director: director} }
func (this *GraphitePublisher) Publish(metrics []Metric) { conn, err := net.DialTimeout(this.protocol, this.address, time.Second*5) if err != nil { log.Error(3, "Metrics: GraphitePublisher: Failed to connect to %s!", err) return } buf := bytes.NewBufferString("") now := time.Now().Unix() for _, m := range metrics { metricName := this.prefix + m.Name() + m.StringifyTags() switch metric := m.(type) { case Counter: this.addCount(buf, metricName+".count", metric.Count(), now) case Gauge: this.addCount(buf, metricName, metric.Value(), now) case Timer: percentiles := metric.Percentiles([]float64{0.25, 0.75, 0.90, 0.99}) this.addCount(buf, metricName+".count", metric.Count(), now) this.addInt(buf, metricName+".max", metric.Max(), now) this.addInt(buf, metricName+".min", metric.Min(), now) this.addFloat(buf, metricName+".mean", metric.Mean(), now) this.addFloat(buf, metricName+".std", metric.StdDev(), now) this.addFloat(buf, metricName+".p25", percentiles[0], now) this.addFloat(buf, metricName+".p75", percentiles[1], now) this.addFloat(buf, metricName+".p90", percentiles[2], now) this.addFloat(buf, metricName+".p99", percentiles[3], now) } } log.Trace("Metrics: GraphitePublisher.Publish() \n%s", buf) _, err = conn.Write(buf.Bytes()) if err != nil { log.Error(3, "Metrics: GraphitePublisher: Failed to send metrics! %s", err) } }
func sendUsageStats() { log.Trace("Sending anonymous usage stats to stats.grafana.org") version := strings.Replace(setting.BuildVersion, ".", "_", -1) metrics := map[string]interface{}{} report := map[string]interface{}{ "version": version, "metrics": metrics, } statsQuery := m.GetSystemStatsQuery{} if err := bus.Dispatch(&statsQuery); err != nil { log.Error(3, "Failed to get system stats", err) return } UsageStats.Each(func(name string, i interface{}) { switch metric := i.(type) { case Counter: if metric.Count() > 0 { metrics[name+".count"] = metric.Count() metric.Clear() } } }) metrics["stats.dashboards.count"] = statsQuery.Result.DashboardCount metrics["stats.users.count"] = statsQuery.Result.UserCount metrics["stats.orgs.count"] = statsQuery.Result.OrgCount out, _ := json.Marshal(report) data := bytes.NewBuffer(out) client := http.Client{Timeout: time.Duration(5 * time.Second)} go client.Post("https://stats.grafana.org/grafana-usage-report", "application/json", data) }
func DeleteOrg(cmd *m.DeleteOrgCommand) error { return inTransaction2(func(sess *session) error { deletes := []string{ "DELETE FROM star WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ?)", "DELETE FROM dashboard_tag WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ?)", "DELETE FROM dashboard WHERE org_id = ?", "DELETE FROM api_key WHERE org_id = ?", "DELETE FROM data_source WHERE org_id = ?", "DELETE FROM org_user WHERE org_id = ?", "DELETE FROM org WHERE id = ?", } for _, sql := range deletes { log.Trace(sql) _, err := sess.Exec(sql, cmd.Id) if err != nil { return err } } return nil }) }
func buildAndSend(msg *Message) (int, error) { log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) // get message body content := msg.Content() if len(msg.To) == 0 { return 0, fmt.Errorf("empty receive emails") } else if len(msg.Body) == 0 { return 0, fmt.Errorf("empty email body") } if msg.Massive { // send mail to multiple emails one by one num := 0 for _, to := range msg.To { body := []byte("To: " + to + "\r\n" + content) err := sendToSmtpServer([]string{to}, body) if err != nil { return num, err } num++ } return num, nil } else { body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) // send to multiple emails in one message err := sendToSmtpServer(msg.To, body) if err != nil { return 0, err } else { return 1, nil } } }
func checkForUpdates() { log.Trace("Checking for updates") client := http.Client{Timeout: time.Duration(5 * time.Second)} pluginSlugs := getAllExternalPluginSlugs() resp, err := client.Get("https://grafana.net/api/plugins/versioncheck?slugIn=" + pluginSlugs + "&grafanaVersion=" + setting.BuildVersion) if err != nil { log.Trace("Failed to get plugins repo from grafana.net, %v", err.Error()) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Trace("Update check failed, reading response from grafana.net, %v", err.Error()) return } gNetPlugins := []GrafanaNetPlugin{} err = json.Unmarshal(body, &gNetPlugins) if err != nil { log.Trace("Failed to unmarshal plugin repo, reading response from grafana.net, %v", err.Error()) return } for _, plug := range Plugins { for _, gplug := range gNetPlugins { if gplug.Slug == plug.Id { plug.GrafanaNetVersion = gplug.Version plug.GrafanaNetHasUpdate = plug.Info.Version != plug.GrafanaNetVersion } } } resp2, err := client.Get("https://raw.githubusercontent.com/grafana/grafana/master/latest.json") if err != nil { log.Trace("Failed to get lates.json repo from github: %v", err.Error()) return } defer resp2.Body.Close() body, err = ioutil.ReadAll(resp2.Body) if err != nil { log.Trace("Update check failed, reading response from github.net, %v", err.Error()) return } var githubLatest GithubLatest err = json.Unmarshal(body, &githubLatest) if err != nil { log.Trace("Failed to unmarshal github latest, reading response from github: %v", err.Error()) return } if strings.Contains(setting.BuildVersion, "-") { GrafanaLatestVersion = githubLatest.Testing GrafanaHasUpdate = !strings.HasPrefix(setting.BuildVersion, githubLatest.Testing) } else { GrafanaLatestVersion = githubLatest.Stable GrafanaHasUpdate = githubLatest.Stable != setting.BuildVersion } }
func (a *keystoneAuther) syncOrgRoles(username, password string, user *m.User) error { log.Trace("syncOrgRoles()") err := a.getProjectList(username, password) if err != nil { return err } log.Debug("OpenStack project_list[roles]: %v", a.project_list) orgsQuery := m.GetUserOrgListQuery{UserId: user.Id} if err := bus.Dispatch(&orgsQuery); err != nil { return err } handledOrgIds := map[int64]bool{} // update or remove org roles for _, org := range orgsQuery.Result { handledOrgIds[org.OrgId] = true log.Info(fmt.Sprintf("Checking Grafana org %v for roles", org.Name)) if user_roles, ok := a.project_list[org.Name]; ok { // Update roles if user belongs to org role_name := a.getRole(user_roles) if role_name != "" { if err := a.updateGrafanaOrgUser(user.Id, org.OrgId, role_name); err != nil { return err } } else { // remove user if no permissions if err := a.removeGrafanaOrgUser(user.Id, org.OrgId); err != nil { return err } } } else { // remove role if no mappings match if err := a.removeGrafanaOrgUser(user.Id, org.OrgId); err != nil { return err } } } // add missing org roles for project, _ := range a.project_list { if grafanaOrg, err := a.getGrafanaOrgFor(project); err != nil { return err } else { if _, exists := handledOrgIds[grafanaOrg.Id]; exists { continue } // add role role_name := a.getRole(a.project_list[project]) if role_name != "" { cmd := m.AddOrgUserCommand{UserId: user.Id, Role: role_name, OrgId: grafanaOrg.Id} if err := bus.Dispatch(&cmd); err != nil { return err } } // mark this tenant has handled so we do not process it again handledOrgIds[grafanaOrg.Id] = true } } // set or unset admin permissions isAdmin := false role_map := make(map[string]bool) for _, role := range a.admin_roles { role_map[role] = true } for project, _ := range a.project_list { if isAdmin == true { break } project_roles := a.project_list[project] for _, role := range project_roles { if _, ok := role_map[role]; ok { isAdmin = true break } } } if isAdmin != user.IsAdmin { if err := a.updateGrafanaUserPermissions(user.Id, isAdmin); err != nil { return err } } orgsQuery = m.GetUserOrgListQuery{UserId: user.Id} if err := bus.Dispatch(&orgsQuery); err != nil { return err } if len(orgsQuery.Result) == 0 { return errors.New("Keystone authentication failed: No grafana permissions") } match := false var orgid int64 for _, org := range orgsQuery.Result { orgid = org.OrgId if user.OrgId == orgid { match = true break } } // set org if none is set (for new users), or if user no longer has permissions for the current org if (user.OrgId == 1) || (match == false) { cmd := m.SetUsingOrgCommand{UserId: user.Id, OrgId: orgid} if err := bus.Dispatch(&cmd); err != nil { return err } } return nil }
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 + "/") }