The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/services/sqlstore/user.go

208 lines
4.8 KiB

// DO NOT ADD METHODS TO THIS FILES. SQLSTORE IS DEPRECATED AND WILL BE REMOVED.
package sqlstore
import (
"context"
"fmt"
"strings"
"time"
"github.com/grafana/grafana/pkg/events"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
)
const mainOrgName = "Main Org."
func (ss *SQLStore) getOrgIDForNewUser(sess *DBSession, args user.CreateUserCommand) (int64, error) {
if ss.Cfg.AutoAssignOrg && args.OrgID != 0 {
if err := verifyExistingOrg(sess, args.OrgID); err != nil {
return -1, err
}
return args.OrgID, nil
}
orgName := args.OrgName
if orgName == "" {
orgName = util.StringsFallback2(args.Email, args.Login)
}
return ss.getOrCreateOrg(sess, orgName)
}
// createUser creates a user in the database. It will also create a default
// organization, if none exists. This should only be used by the sqlstore
// Reset() function.
//
// If AutoAssignOrg is enabled then args.OrgID will be used to add to an
// existing Org with id=args.OrgID. If AutoAssignOrg is disabled then
// args.OrgName will be used to create a new Org with name=args.OrgName. If an
// org already exists with that name, it will error.
func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args user.CreateUserCommand) (user.User, error) {
var usr user.User
orgID, err := ss.getOrgIDForNewUser(sess, args)
if err != nil {
return usr, err
}
if args.Email == "" {
args.Email = args.Login
}
where := "email=? OR login=?"
if ss.Cfg.CaseInsensitiveLogin {
where = "LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)"
args.Login = strings.ToLower(args.Login)
args.Email = strings.ToLower(args.Email)
}
exists, err := sess.Where(where, args.Email, args.Login).Get(&user.User{})
if err != nil {
return usr, err
}
if exists {
return usr, user.ErrUserAlreadyExists
}
// create user
usr = user.User{
Email: args.Email,
Login: args.Login,
IsAdmin: args.IsAdmin,
OrgID: orgID,
Created: TimeNow(),
Updated: TimeNow(),
LastSeenAt: TimeNow().AddDate(-10, 0, 0),
}
salt, err := util.GetRandomString(10)
if err != nil {
return usr, err
}
usr.Salt = salt
rands, err := util.GetRandomString(10)
if err != nil {
return usr, err
}
usr.Rands = rands
if len(args.Password) > 0 {
encodedPassword, err := util.EncodePassword(args.Password, usr.Salt)
if err != nil {
return usr, err
}
usr.Password = encodedPassword
}
sess.UseBool("is_admin")
if _, err := sess.Insert(&usr); err != nil {
return usr, err
}
sess.publishAfterCommit(&events.UserCreated{
Timestamp: usr.Created,
Id: usr.ID,
Name: usr.Name,
Login: usr.Login,
Email: usr.Email,
})
orgUser := models.OrgUser{
OrgId: orgID,
UserId: usr.ID,
Role: org.RoleAdmin,
Created: TimeNow(),
Updated: TimeNow(),
}
if ss.Cfg.AutoAssignOrg && !usr.IsAdmin {
if len(args.DefaultOrgRole) > 0 {
orgUser.Role = org.RoleType(args.DefaultOrgRole)
} else {
orgUser.Role = org.RoleType(ss.Cfg.AutoAssignOrgRole)
}
}
if _, err = sess.Insert(&orgUser); err != nil {
return usr, err
}
return usr, nil
}
func UserDeletions() []string {
deletes := []string{
"DELETE FROM star WHERE user_id = ?",
"DELETE FROM " + dialect.Quote("user") + " WHERE id = ?",
"DELETE FROM org_user WHERE user_id = ?",
"DELETE FROM dashboard_acl WHERE user_id = ?",
"DELETE FROM preferences WHERE user_id = ?",
"DELETE FROM team_member WHERE user_id = ?",
"DELETE FROM user_auth WHERE user_id = ?",
"DELETE FROM user_auth_token WHERE user_id = ?",
"DELETE FROM quota WHERE user_id = ?",
}
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>
4 years ago
return deletes
}
func verifyExistingOrg(sess *DBSession, orgId int64) error {
var org models.Org
has, err := sess.Where("id=?", orgId).Get(&org)
if err != nil {
return err
}
if !has {
return models.ErrOrgNotFound
}
return nil
}
func (ss *SQLStore) getOrCreateOrg(sess *DBSession, orgName string) (int64, error) {
var org models.Org
if ss.Cfg.AutoAssignOrg {
has, err := sess.Where("id=?", ss.Cfg.AutoAssignOrgId).Get(&org)
if err != nil {
return 0, err
}
if has {
return org.Id, nil
}
if ss.Cfg.AutoAssignOrgId != 1 {
ss.log.Error("Could not create user: organization ID does not exist", "orgID",
ss.Cfg.AutoAssignOrgId)
return 0, fmt.Errorf("could not create user: organization ID %d does not exist",
ss.Cfg.AutoAssignOrgId)
}
org.Name = mainOrgName
org.Id = int64(ss.Cfg.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
}