Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User traits editor UI #42620

Merged
merged 33 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
44925dd
editor mockup
flyinghermit Jun 6, 2024
67a92fc
add empty traits to available traits so user can select from dropdown
flyinghermit Jun 6, 2024
a103b2a
trait name and value editor
flyinghermit Jun 7, 2024
b9ae408
transform editor data to match with onSave func
flyinghermit Jun 7, 2024
e7616af
add new trait
flyinghermit Jun 7, 2024
aad4b5f
remove trait
flyinghermit Jun 7, 2024
ecec976
add available trait name list
flyinghermit Jun 7, 2024
30a133d
show traits header only when trait count is more than zero
flyinghermit Jun 7, 2024
715a04c
add duplicate trait rule, add requireAll wrapper to shared rules
flyinghermit Jun 10, 2024
8001bdd
update editor design
flyinghermit Jun 10, 2024
2a914e9
move TraitsEditor to separate file, add unit test
flyinghermit Jun 10, 2024
7872c76
Merge branch 'master' into sshah/user-traits-editor
flyinghermit Jun 10, 2024
6dde19b
fix edit story
flyinghermit Jun 10, 2024
58d6a79
update /users API to handle allTraits
flyinghermit Jun 10, 2024
b015d03
cleanup
flyinghermit Jun 10, 2024
ca0520e
prettier format
flyinghermit Jun 10, 2024
f5d24c8
move validation rule out from TraitsEditor component
flyinghermit Jun 10, 2024
5ac8f30
remove requiredAll rule wrapper
flyinghermit Jun 10, 2024
8965089
Merge branch 'master' into sshah/user-traits-editor
flyinghermit Jun 11, 2024
11c7330
Merge branch 'master' of github.com:gravitational/teleport into sshah…
flyinghermit Jun 11, 2024
0d6b589
rename trait vars and add api unit test:
flyinghermit Jun 11, 2024
2f13357
fix typo's, add js comments
flyinghermit Jun 11, 2024
1a39fd7
use pointer to traitsPreset so empty struct can be compared with nil
flyinghermit Jun 12, 2024
314783e
resovle review comments:
flyinghermit Jun 13, 2024
1a98872
remove describe
flyinghermit Jun 13, 2024
23e8524
use const for array, bring back commented empty string checker block
flyinghermit Jun 13, 2024
7d4ecd8
add maxWidth to DialogContent inner content to avoid flickering when …
flyinghermit Jun 13, 2024
c3b9777
resolve review comments
flyinghermit Jun 13, 2024
47df76a
filter empty element only if length equals 1. add unit test
flyinghermit Jun 13, 2024
1d38fb3
handlechange: return for empty string, trim whitespace
flyinghermit Jun 13, 2024
1e80fcf
explicitely handle null value
flyinghermit Jun 13, 2024
9a239ba
shorten empty string value check block
flyinghermit Jun 14, 2024
4c868e3
Merge branch 'master' into sshah/user-traits-editor
flyinghermit Jun 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 57 additions & 25 deletions lib/web/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,16 @@ func createUser(r *http.Request, m userAPIGetter, createdBy string) (*ui.User, e

user.SetRoles(req.Roles)

updateUserTraits(req, user)
// checkAndSetDefaults makes sure either TraitsPreset
// or AllTraits field to be populated. Since empty
// AllTraits is also used to delete all user traits,
// we explicitly check if TraitsPreset is empty so
// to prevent traits deletion.
if req.TraitsPreset == nil {
user.SetTraits(req.AllTraits)
} else {
updateUserTraitsPreset(req, user)
}

user.SetCreatedBy(types.CreatedBy{
User: types.UserRef{Name: createdBy},
Expand All @@ -119,30 +128,30 @@ func createUser(r *http.Request, m userAPIGetter, createdBy string) (*ui.User, e
return ui.NewUser(created)
}

// updateUserTraits receives a saveUserRequest and updates the user traits accordingly
// It only updates the traits that have a non-nil value in saveUserRequest
// This allows the partial update of the properties
func updateUserTraits(req *saveUserRequest, user types.User) {
if req.Traits.Logins != nil {
user.SetLogins(*req.Traits.Logins)
// updateUserTraitsPreset receives a saveUserRequest and updates the user traits
// accordingly. It only updates the traits that have a non-nil value in
// saveUserRequest. This allows the partial update of the properties
func updateUserTraitsPreset(req *saveUserRequest, user types.User) {
if req.TraitsPreset.Logins != nil {
user.SetLogins(*req.TraitsPreset.Logins)
}
if req.Traits.DatabaseUsers != nil {
user.SetDatabaseUsers(*req.Traits.DatabaseUsers)
if req.TraitsPreset.DatabaseUsers != nil {
user.SetDatabaseUsers(*req.TraitsPreset.DatabaseUsers)
}
if req.Traits.DatabaseNames != nil {
user.SetDatabaseNames(*req.Traits.DatabaseNames)
if req.TraitsPreset.DatabaseNames != nil {
user.SetDatabaseNames(*req.TraitsPreset.DatabaseNames)
}
if req.Traits.KubeUsers != nil {
user.SetKubeUsers(*req.Traits.KubeUsers)
if req.TraitsPreset.KubeUsers != nil {
user.SetKubeUsers(*req.TraitsPreset.KubeUsers)
}
if req.Traits.KubeGroups != nil {
user.SetKubeGroups(*req.Traits.KubeGroups)
if req.TraitsPreset.KubeGroups != nil {
user.SetKubeGroups(*req.TraitsPreset.KubeGroups)
}
if req.Traits.WindowsLogins != nil {
user.SetWindowsLogins(*req.Traits.WindowsLogins)
if req.TraitsPreset.WindowsLogins != nil {
user.SetWindowsLogins(*req.TraitsPreset.WindowsLogins)
}
if req.Traits.AWSRoleARNs != nil {
user.SetAWSRoleARNs(*req.Traits.AWSRoleARNs)
if req.TraitsPreset.AWSRoleARNs != nil {
user.SetAWSRoleARNs(*req.TraitsPreset.AWSRoleARNs)
}
}

Expand All @@ -169,7 +178,16 @@ func updateUser(r *http.Request, m userAPIGetter) (*ui.User, error) {

user.SetRoles(req.Roles)

updateUserTraits(req, user)
// checkAndSetDefaults makes sure either TraitsPreset
// or AllTraits field to be populated. Since empty
// AllTraits is also used to delete all user traits,
// we explicitly check if TraitsPreset is empty so
// to prevent traits deletion.
if req.TraitsPreset == nil {
user.SetTraits(req.AllTraits)
} else {
updateUserTraitsPreset(req, user)
}
flyinghermit marked this conversation as resolved.
Show resolved Hide resolved

updated, err := m.UpdateUser(r.Context(), user)
if err != nil {
Expand Down Expand Up @@ -287,7 +305,8 @@ type userAPIGetter interface {
DeleteUser(ctx context.Context, user string) error
}

type userTraits struct {
// traitsPreset are user traits that are pre-defined in Teleport
type traitsPreset struct {
Logins *[]string `json:"logins,omitempty"`
DatabaseUsers *[]string `json:"databaseUsers,omitempty"`
DatabaseNames *[]string `json:"databaseNames,omitempty"`
Expand All @@ -303,11 +322,21 @@ type userTraits struct {
// They are optional and respect the following logic:
// - if the value is nil, we ignore it
// - if the value is an empty array we remove every element from the trait
// - otherwise, we replace the list for that trait
// - otherwise, we replace the list for that trait.
// Use TraitsPreset to selectively update traits.
// Use AllTraits to fully replace existing traits.
type saveUserRequest struct {
Name string `json:"name"`
Roles []string `json:"roles"`
Traits userTraits `json:"traits"`
// Name is username.
Name string `json:"name"`
// Roles is slice of user roles assigned to user.
Roles []string `json:"roles"`
// TraitsPreset holds traits that are pre-defined in Teleport.
// Clients may use TraitsPreset to selectively update user traits.
TraitsPreset *traitsPreset `json:"traits"`
// AllTraits may hold all the user traits, including traits key defined
// in TraitsPreset and/or new trait key values defined by Teleport admin.
// AllTraits should be used to fully replace and update user traits.
AllTraits map[string][]string `json:"allTraits"`
flyinghermit marked this conversation as resolved.
Show resolved Hide resolved
}

func (r *saveUserRequest) checkAndSetDefaults() error {
flyinghermit marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -317,5 +346,8 @@ func (r *saveUserRequest) checkAndSetDefaults() error {
if len(r.Roles) == 0 {
return trace.BadParameter("missing roles")
}
if len(r.AllTraits) != 0 && r.TraitsPreset != nil {
return trace.BadParameter("either traits or allTraits must be provided")
}
return nil
}
Loading
Loading