mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-11-04 01:25:06 +01:00 
			
		
		
		
	Add role helper functions, add project role barebone, add valid role arr
- HasAnyRoles([]string): Checks if user has *one* of the roles - HasAllRoles([]string): Cheks if user has *all* of the roles - HasNotRoles([]string): Checks if user has *none* of the roles - IsValidRole(string): Checks if given string is known valid role
This commit is contained in:
		internal
@@ -23,8 +23,11 @@ const (
 | 
				
			|||||||
	RoleSupport string = "support"
 | 
						RoleSupport string = "support"
 | 
				
			||||||
	RoleApi     string = "api"
 | 
						RoleApi     string = "api"
 | 
				
			||||||
	RoleUser    string = "user"
 | 
						RoleUser    string = "user"
 | 
				
			||||||
 | 
						RoleProject string = "project"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var validRoles = [5]string{RoleAdmin, RoleSupport, RoleApi, RoleUser, RoleProject}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AuthViaLocalPassword int8 = 0
 | 
						AuthViaLocalPassword int8 = 0
 | 
				
			||||||
	AuthViaLDAP          int8 = 1
 | 
						AuthViaLDAP          int8 = 1
 | 
				
			||||||
@@ -38,6 +41,7 @@ type User struct {
 | 
				
			|||||||
	Roles      []string `json:"roles"`
 | 
						Roles      []string `json:"roles"`
 | 
				
			||||||
	AuthSource int8     `json:"via"`
 | 
						AuthSource int8     `json:"via"`
 | 
				
			||||||
	Email      string   `json:"email"`
 | 
						Email      string   `json:"email"`
 | 
				
			||||||
 | 
						Project    string   `json:"project"`
 | 
				
			||||||
	Expiration time.Time
 | 
						Expiration time.Time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,6 +54,66 @@ func (u *User) HasRole(role string) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Role-Arrays are short: performance not impacted by nested loop
 | 
				
			||||||
 | 
					func (u *User) HasAnyRole(queryroles []string) bool {
 | 
				
			||||||
 | 
						for _, ur := range u.Roles {
 | 
				
			||||||
 | 
							for _, qr := range queryroles {
 | 
				
			||||||
 | 
								if ur == qr {
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Role-Arrays are short: performance not impacted by nested loop
 | 
				
			||||||
 | 
					func (u *User) HasAllRoles(queryroles []string) bool {
 | 
				
			||||||
 | 
						target 	:= len(queryroles)
 | 
				
			||||||
 | 
						matches := 0
 | 
				
			||||||
 | 
						for _, ur := range u.Roles {
 | 
				
			||||||
 | 
							for _, qr := range queryroles {
 | 
				
			||||||
 | 
								if ur == qr {
 | 
				
			||||||
 | 
									matches += 1
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if matches == target {
 | 
				
			||||||
 | 
						  return true
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Role-Arrays are short: performance not impacted by nested loop
 | 
				
			||||||
 | 
					func (u *User) HasNotRoles(queryroles []string) bool {
 | 
				
			||||||
 | 
						matches := 0
 | 
				
			||||||
 | 
						for _, ur := range u.Roles {
 | 
				
			||||||
 | 
							for _, qr := range queryroles {
 | 
				
			||||||
 | 
								if ur == qr {
 | 
				
			||||||
 | 
									matches += 1
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if matches == 0 {
 | 
				
			||||||
 | 
						  return true
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsValidRole(role string) bool {
 | 
				
			||||||
 | 
						for _, r := range validRoles {
 | 
				
			||||||
 | 
							if r == role {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetUser(ctx context.Context) *User {
 | 
					func GetUser(ctx context.Context) *User {
 | 
				
			||||||
	x := ctx.Value(ContextUserKey)
 | 
						x := ctx.Value(ContextUserKey)
 | 
				
			||||||
	if x == nil {
 | 
						if x == nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,14 +120,12 @@ func (auth *Authentication) AddRole(
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if role != RoleAdmin && role != RoleApi && role != RoleUser && role != RoleSupport {
 | 
						if !IsValidRole(role) {
 | 
				
			||||||
		return fmt.Errorf("invalid user role: %#v", role)
 | 
							return fmt.Errorf("invalid user role: %#v", role)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, r := range user.Roles {
 | 
						if user.HasRole(role) {
 | 
				
			||||||
		if r == role {
 | 
							return fmt.Errorf("user %#v already has role %#v", username, role)
 | 
				
			||||||
			return fmt.Errorf("user %#v already has role %#v", username, role)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	roles, _ := json.Marshal(append(user.Roles, role))
 | 
						roles, _ := json.Marshal(append(user.Roles, role))
 | 
				
			||||||
@@ -143,7 +141,7 @@ func (auth *Authentication) RemoveRole(ctx context.Context, username string, rol
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if role != RoleAdmin && role != RoleApi && role != RoleUser && role != RoleSupport {
 | 
						if !IsValidRole(role) {
 | 
				
			||||||
		return fmt.Errorf("invalid user role: %#v", role)
 | 
							return fmt.Errorf("invalid user role: %#v", role)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -170,7 +168,7 @@ func (auth *Authentication) RemoveRole(ctx context.Context, username string, rol
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func FetchUser(ctx context.Context, db *sqlx.DB, username string) (*model.User, error) {
 | 
					func FetchUser(ctx context.Context, db *sqlx.DB, username string) (*model.User, error) {
 | 
				
			||||||
	me := GetUser(ctx)
 | 
						me := GetUser(ctx)
 | 
				
			||||||
	if me != nil && !me.HasRole(RoleAdmin) && !me.HasRole(RoleSupport) && me.Username != username {
 | 
						if me != nil && me.Username != username && me.HasNotRoles([]string{RoleAdmin, RoleSupport}) {
 | 
				
			||||||
		return nil, errors.New("forbidden")
 | 
							return nil, errors.New("forbidden")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -152,7 +152,7 @@ func (r *queryResolver) Job(ctx context.Context, id string) (*schema.Job, error)
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if user := auth.GetUser(ctx); user != nil && !user.HasRole(auth.RoleAdmin) && !user.HasRole(auth.RoleSupport) && job.User != user.Username {
 | 
						if user := auth.GetUser(ctx); user != nil && job.User != user.Username && user.HasNotRoles([]string{auth.RoleAdmin, auth.RoleSupport}){
 | 
				
			||||||
		return nil, errors.New("you are not allowed to see this job")
 | 
							return nil, errors.New("you are not allowed to see this job")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -423,7 +423,7 @@ func (r *JobRepository) FindJobOrUser(ctx context.Context, searchterm string) (j
 | 
				
			|||||||
	user := auth.GetUser(ctx)
 | 
						user := auth.GetUser(ctx)
 | 
				
			||||||
	if id, err := strconv.Atoi(searchterm); err == nil {
 | 
						if id, err := strconv.Atoi(searchterm); err == nil {
 | 
				
			||||||
		qb := sq.Select("job.id").From("job").Where("job.job_id = ?", id)
 | 
							qb := sq.Select("job.id").From("job").Where("job.job_id = ?", id)
 | 
				
			||||||
		if user != nil && !user.HasRole(auth.RoleAdmin) && !user.HasRole(auth.RoleSupport) {
 | 
							if user != nil && user.HasNotRoles([]string{auth.RoleAdmin, auth.RoleSupport}) {
 | 
				
			||||||
			qb = qb.Where("job.user = ?", user.Username)
 | 
								qb = qb.Where("job.user = ?", user.Username)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -435,7 +435,7 @@ func (r *JobRepository) FindJobOrUser(ctx context.Context, searchterm string) (j
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if user == nil || user.HasRole(auth.RoleAdmin) || user.HasRole(auth.RoleSupport) {
 | 
						if user == nil || user.HasAnyRole([]string{auth.RoleAdmin, auth.RoleSupport}) {
 | 
				
			||||||
		err := sq.Select("job.user").Distinct().From("job").
 | 
							err := sq.Select("job.user").Distinct().From("job").
 | 
				
			||||||
			Where("job.user = ?", searchterm).
 | 
								Where("job.user = ?", searchterm).
 | 
				
			||||||
			RunWith(r.stmtCache).QueryRow().Scan(&username)
 | 
								RunWith(r.stmtCache).QueryRow().Scan(&username)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,7 +94,7 @@ func (r *JobRepository) CountJobs(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func SecurityCheck(ctx context.Context, query sq.SelectBuilder) sq.SelectBuilder {
 | 
					func SecurityCheck(ctx context.Context, query sq.SelectBuilder) sq.SelectBuilder {
 | 
				
			||||||
	user := auth.GetUser(ctx)
 | 
						user := auth.GetUser(ctx)
 | 
				
			||||||
	if user == nil || user.HasRole(auth.RoleAdmin) || user.HasRole(auth.RoleApi) || user.HasRole(auth.RoleSupport) {
 | 
						if user == nil || user.HasAnyRole([]string{auth.RoleAdmin, auth.RoleApi, auth.RoleSupport}) {
 | 
				
			||||||
		return query
 | 
							return query
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user