mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			234 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Go
		
	
	
	
package database
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/grafana/grafana/pkg/infra/db"
 | 
						|
	"github.com/grafana/grafana/pkg/services/accesscontrol"
 | 
						|
)
 | 
						|
 | 
						|
func ProvideService(sql db.DB) *AccessControlStore {
 | 
						|
	return &AccessControlStore{sql}
 | 
						|
}
 | 
						|
 | 
						|
type AccessControlStore struct {
 | 
						|
	sql db.DB
 | 
						|
}
 | 
						|
 | 
						|
func (s *AccessControlStore) GetUserPermissions(ctx context.Context, query accesscontrol.GetUserPermissionsQuery) ([]accesscontrol.Permission, error) {
 | 
						|
	result := make([]accesscontrol.Permission, 0)
 | 
						|
	err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
 | 
						|
		if query.UserID == 0 && len(query.TeamIDs) == 0 && len(query.Roles) == 0 {
 | 
						|
			// no permission to fetch
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
 | 
						|
		filter, params := accesscontrol.UserRolesFilter(query.OrgID, query.UserID, query.TeamIDs, query.Roles)
 | 
						|
 | 
						|
		q := `
 | 
						|
		SELECT
 | 
						|
			permission.action,
 | 
						|
			permission.scope
 | 
						|
			FROM permission
 | 
						|
			INNER JOIN role ON role.id = permission.role_id
 | 
						|
		` + filter
 | 
						|
 | 
						|
		if query.RolePrefix != "" {
 | 
						|
			q += " WHERE role.name LIKE ?"
 | 
						|
			params = append(params, query.RolePrefix+"%")
 | 
						|
		}
 | 
						|
 | 
						|
		if err := sess.SQL(q, params...).Find(&result); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	})
 | 
						|
 | 
						|
	return result, err
 | 
						|
}
 | 
						|
 | 
						|
// SearchUsersPermissions returns the list of user permissions indexed by UserID
 | 
						|
func (s *AccessControlStore) SearchUsersPermissions(ctx context.Context, orgID int64, options accesscontrol.SearchOptions) (map[int64][]accesscontrol.Permission, error) {
 | 
						|
	type UserRBACPermission struct {
 | 
						|
		UserID int64  `xorm:"user_id"`
 | 
						|
		Action string `xorm:"action"`
 | 
						|
		Scope  string `xorm:"scope"`
 | 
						|
	}
 | 
						|
	dbPerms := make([]UserRBACPermission, 0)
 | 
						|
	if err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
 | 
						|
		// Find permissions
 | 
						|
		q := `
 | 
						|
		SELECT
 | 
						|
			user_id,
 | 
						|
			action,
 | 
						|
			scope
 | 
						|
		FROM (
 | 
						|
			SELECT ur.user_id, ur.org_id, p.action, p.scope
 | 
						|
				FROM permission AS p
 | 
						|
				INNER JOIN user_role AS ur on ur.role_id = p.role_id
 | 
						|
			UNION ALL
 | 
						|
				SELECT tm.user_id, tr.org_id, p.action, p.scope
 | 
						|
					FROM permission AS p
 | 
						|
					INNER JOIN team_role AS tr ON tr.role_id = p.role_id
 | 
						|
					INNER JOIN team_member AS tm ON tm.team_id = tr.team_id
 | 
						|
			UNION ALL
 | 
						|
				SELECT ou.user_id, br.org_id, p.action, p.scope
 | 
						|
					FROM permission AS p
 | 
						|
					INNER JOIN builtin_role AS br ON br.role_id = p.role_id
 | 
						|
					INNER JOIN org_user AS ou ON ou.role = br.role
 | 
						|
			UNION ALL
 | 
						|
				SELECT sa.user_id, br.org_id, p.action, p.scope
 | 
						|
					FROM permission AS p
 | 
						|
					INNER JOIN builtin_role AS br ON br.role_id = p.role_id
 | 
						|
					INNER JOIN (
 | 
						|
						SELECT u.id AS user_id
 | 
						|
						FROM ` + s.sql.GetDialect().Quote("user") + ` AS u WHERE u.is_admin
 | 
						|
					) AS sa ON 1 = 1
 | 
						|
					WHERE br.role = ?
 | 
						|
		) AS up
 | 
						|
		WHERE (org_id = ? OR org_id = ?)
 | 
						|
		`
 | 
						|
 | 
						|
		params := []interface{}{accesscontrol.RoleGrafanaAdmin, accesscontrol.GlobalOrgID, orgID}
 | 
						|
 | 
						|
		if options.ActionPrefix != "" {
 | 
						|
			q += ` AND action LIKE ?`
 | 
						|
			params = append(params, options.ActionPrefix+"%")
 | 
						|
		}
 | 
						|
		if options.Action != "" {
 | 
						|
			q += ` AND action = ?`
 | 
						|
			params = append(params, options.Action)
 | 
						|
		}
 | 
						|
		if options.Scope != "" {
 | 
						|
			q += ` AND scope = ?`
 | 
						|
			params = append(params, options.Scope)
 | 
						|
		}
 | 
						|
 | 
						|
		if options.UserID != 0 {
 | 
						|
			q += ` AND user_id = ?`
 | 
						|
			params = append(params, options.UserID)
 | 
						|
		}
 | 
						|
 | 
						|
		return sess.SQL(q, params...).
 | 
						|
			Find(&dbPerms)
 | 
						|
	}); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	mapped := map[int64][]accesscontrol.Permission{}
 | 
						|
	for i := range dbPerms {
 | 
						|
		mapped[dbPerms[i].UserID] = append(mapped[dbPerms[i].UserID], accesscontrol.Permission{Action: dbPerms[i].Action, Scope: dbPerms[i].Scope})
 | 
						|
	}
 | 
						|
 | 
						|
	return mapped, nil
 | 
						|
}
 | 
						|
 | 
						|
// GetUsersBasicRoles returns the list of user basic roles (Admin, Editor, Viewer, Grafana Admin) indexed by UserID
 | 
						|
func (s *AccessControlStore) GetUsersBasicRoles(ctx context.Context, userFilter []int64, orgID int64) (map[int64][]string, error) {
 | 
						|
	type UserOrgRole struct {
 | 
						|
		UserID  int64  `xorm:"id"`
 | 
						|
		OrgRole string `xorm:"role"`
 | 
						|
		IsAdmin bool   `xorm:"is_admin"`
 | 
						|
	}
 | 
						|
	dbRoles := make([]UserOrgRole, 0)
 | 
						|
	if err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
 | 
						|
		// Find roles
 | 
						|
		q := `
 | 
						|
		SELECT u.id, ou.role, u.is_admin
 | 
						|
		FROM ` + s.sql.GetDialect().Quote("user") + ` AS u
 | 
						|
		LEFT JOIN org_user AS ou ON u.id = ou.user_id
 | 
						|
		WHERE (u.is_admin OR ou.org_id = ?)
 | 
						|
		`
 | 
						|
		params := []interface{}{orgID}
 | 
						|
		if len(userFilter) > 0 {
 | 
						|
			q += "AND u.id IN (?" + strings.Repeat(",?", len(userFilter)-1) + ")"
 | 
						|
			for _, u := range userFilter {
 | 
						|
				params = append(params, u)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return sess.SQL(q, params...).Find(&dbRoles)
 | 
						|
	}); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	roles := map[int64][]string{}
 | 
						|
	for i := range dbRoles {
 | 
						|
		if dbRoles[i].OrgRole != "" {
 | 
						|
			roles[dbRoles[i].UserID] = []string{dbRoles[i].OrgRole}
 | 
						|
		}
 | 
						|
		if dbRoles[i].IsAdmin {
 | 
						|
			roles[dbRoles[i].UserID] = append(roles[dbRoles[i].UserID], accesscontrol.RoleGrafanaAdmin)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return roles, nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *AccessControlStore) DeleteUserPermissions(ctx context.Context, orgID, userID int64) error {
 | 
						|
	err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
 | 
						|
		roleDeleteQuery := "DELETE FROM user_role WHERE user_id = ?"
 | 
						|
		roleDeleteParams := []interface{}{roleDeleteQuery, userID}
 | 
						|
		if orgID != accesscontrol.GlobalOrgID {
 | 
						|
			roleDeleteQuery += " AND org_id = ?"
 | 
						|
			roleDeleteParams = []interface{}{roleDeleteQuery, userID, orgID}
 | 
						|
		}
 | 
						|
 | 
						|
		// Delete user role assignments
 | 
						|
		if _, err := sess.Exec(roleDeleteParams...); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		// only delete scopes to user if all permissions is removed (i.e. user is removed)
 | 
						|
		if orgID == accesscontrol.GlobalOrgID {
 | 
						|
			// Delete permissions that are scoped to user
 | 
						|
			if _, err := sess.Exec("DELETE FROM permission WHERE scope = ?", accesscontrol.Scope("users", "id", strconv.FormatInt(userID, 10))); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		roleQuery := "SELECT id FROM role WHERE name = ?"
 | 
						|
		roleParams := []interface{}{accesscontrol.ManagedUserRoleName(userID)}
 | 
						|
		if orgID != accesscontrol.GlobalOrgID {
 | 
						|
			roleQuery += " AND org_id = ?"
 | 
						|
			roleParams = []interface{}{accesscontrol.ManagedUserRoleName(userID), orgID}
 | 
						|
		}
 | 
						|
 | 
						|
		var roleIDs []int64
 | 
						|
		if err := sess.SQL(roleQuery, roleParams...).Find(&roleIDs); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if len(roleIDs) == 0 {
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
 | 
						|
		permissionDeleteQuery := "DELETE FROM permission WHERE role_id IN(? " + strings.Repeat(",?", len(roleIDs)-1) + ")"
 | 
						|
		permissionDeleteParams := make([]interface{}, 0, len(roleIDs)+1)
 | 
						|
		permissionDeleteParams = append(permissionDeleteParams, permissionDeleteQuery)
 | 
						|
		for _, id := range roleIDs {
 | 
						|
			permissionDeleteParams = append(permissionDeleteParams, id)
 | 
						|
		}
 | 
						|
 | 
						|
		// Delete managed user permissions
 | 
						|
		if _, err := sess.Exec(permissionDeleteParams...); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		managedRoleDeleteQuery := "DELETE FROM role WHERE id IN(? " + strings.Repeat(",?", len(roleIDs)-1) + ")"
 | 
						|
		managedRoleDeleteParams := []interface{}{managedRoleDeleteQuery}
 | 
						|
		for _, id := range roleIDs {
 | 
						|
			managedRoleDeleteParams = append(managedRoleDeleteParams, id)
 | 
						|
		}
 | 
						|
		// Delete managed user roles
 | 
						|
		if _, err := sess.Exec(managedRoleDeleteParams...); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	})
 | 
						|
	return err
 | 
						|
}
 |