2017-10-30 18:31:19 +00:00
|
|
|
package organizations
|
2017-10-24 17:29:46 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/influxdata/chronograf"
|
|
|
|
)
|
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
// Ensure UsersStore implements chronograf.UsersStore.
|
|
|
|
var _ chronograf.UsersStore = &UsersStore{}
|
2017-10-24 17:29:46 +00:00
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
// UsersStore uses bolt to store and retrieve users
|
|
|
|
type UsersStore struct {
|
2017-10-31 21:40:58 +00:00
|
|
|
organization string
|
|
|
|
store chronograf.UsersStore
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 21:40:58 +00:00
|
|
|
func NewUsersStore(s chronograf.UsersStore, org string) *UsersStore {
|
2017-10-30 18:31:19 +00:00
|
|
|
return &UsersStore{
|
2017-10-31 21:40:58 +00:00
|
|
|
store: s,
|
|
|
|
organization: org,
|
2017-10-24 20:53:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 16:28:57 +00:00
|
|
|
// validOrganizationRoles ensures that each User Role has both an associated Organization and a Name
|
2017-10-24 21:04:48 +00:00
|
|
|
func validOrganizationRoles(orgID string, u *chronograf.User) error {
|
2017-10-24 17:29:46 +00:00
|
|
|
if u == nil || u.Roles == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
for _, r := range u.Roles {
|
2017-10-30 16:28:57 +00:00
|
|
|
if r.Organization == "" {
|
|
|
|
return fmt.Errorf("user role must have an Organization")
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
2017-10-30 16:28:57 +00:00
|
|
|
if r.Organization != orgID {
|
|
|
|
return fmt.Errorf("organizationID %s does not match %s", r.Organization, orgID)
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
|
|
|
if r.Name == "" {
|
|
|
|
return fmt.Errorf("user role must have a Name")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
// Get searches the UsersStore for user with name
|
|
|
|
func (s *UsersStore) Get(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
2017-10-31 21:40:58 +00:00
|
|
|
err := validOrganization(ctx)
|
2017-10-24 20:53:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
2017-10-31 21:40:58 +00:00
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
usr, err := s.store.Get(ctx, q)
|
2017-10-24 17:29:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// filter Roles that are not scoped to this Organization
|
|
|
|
roles := usr.Roles[:0]
|
|
|
|
for _, r := range usr.Roles {
|
2017-10-31 21:40:58 +00:00
|
|
|
if r.Organization == s.organization {
|
2017-10-24 17:29:46 +00:00
|
|
|
roles = append(roles, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(roles) == 0 {
|
|
|
|
// This means that the user has no roles in an organization
|
|
|
|
// TODO: should we return the user without any roles or ErrUserNotFound?
|
|
|
|
return nil, chronograf.ErrUserNotFound
|
|
|
|
}
|
|
|
|
usr.Roles = roles
|
|
|
|
return usr, nil
|
|
|
|
}
|
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
// Add a new User to the UsersStore.
|
|
|
|
func (s *UsersStore) Add(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
|
2017-10-31 21:40:58 +00:00
|
|
|
err := validOrganization(ctx)
|
2017-10-24 20:53:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
2017-10-31 21:40:58 +00:00
|
|
|
|
|
|
|
if err := validOrganizationRoles(s.organization, u); err != nil {
|
2017-10-24 17:29:46 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-10-30 18:31:19 +00:00
|
|
|
usr, err := s.store.Get(ctx, chronograf.UserQuery{
|
2017-10-24 21:53:44 +00:00
|
|
|
Name: &u.Name,
|
|
|
|
Provider: &u.Provider,
|
|
|
|
Scheme: &u.Scheme,
|
|
|
|
})
|
|
|
|
if err != nil && err != chronograf.ErrUserNotFound {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err == chronograf.ErrUserNotFound {
|
2017-10-30 18:31:19 +00:00
|
|
|
return s.store.Add(ctx, u)
|
2017-10-24 21:53:44 +00:00
|
|
|
}
|
|
|
|
usr.Roles = append(usr.Roles, u.Roles...)
|
2017-10-30 18:31:19 +00:00
|
|
|
if err := s.store.Update(ctx, usr); err != nil {
|
2017-10-24 21:53:44 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
u.ID = usr.ID
|
|
|
|
return u, nil
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
// Delete a user from the UsersStore
|
|
|
|
func (s *UsersStore) Delete(ctx context.Context, usr *chronograf.User) error {
|
2017-10-31 21:40:58 +00:00
|
|
|
err := validOrganization(ctx)
|
2017-10-24 20:53:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
2017-10-30 18:31:19 +00:00
|
|
|
u, err := s.store.Get(ctx, chronograf.UserQuery{ID: &usr.ID})
|
2017-10-24 17:29:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// delete Roles that are not scoped to this Organization
|
|
|
|
roles := u.Roles[:0]
|
|
|
|
for _, r := range u.Roles {
|
2017-10-31 21:40:58 +00:00
|
|
|
if r.Organization != s.organization {
|
2017-10-24 17:29:46 +00:00
|
|
|
roles = append(roles, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u.Roles = roles
|
2017-10-30 18:31:19 +00:00
|
|
|
return s.store.Update(ctx, u)
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update a user
|
2017-10-30 18:31:19 +00:00
|
|
|
func (s *UsersStore) Update(ctx context.Context, usr *chronograf.User) error {
|
2017-10-31 21:40:58 +00:00
|
|
|
err := validOrganization(ctx)
|
2017-10-24 20:53:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
2017-10-31 21:40:58 +00:00
|
|
|
|
|
|
|
if err := validOrganizationRoles(s.organization, usr); err != nil {
|
2017-10-24 17:29:46 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-10-30 18:31:19 +00:00
|
|
|
u, err := s.store.Get(ctx, chronograf.UserQuery{ID: &usr.ID})
|
2017-10-24 17:29:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// filter Roles that are not scoped to this Organization
|
|
|
|
roles := u.Roles[:0]
|
|
|
|
for _, r := range u.Roles {
|
2017-10-31 21:40:58 +00:00
|
|
|
if r.Organization != s.organization {
|
2017-10-24 17:29:46 +00:00
|
|
|
roles = append(roles, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-24 21:04:05 +00:00
|
|
|
// recombine roles from usr, by replacing the roles of the user
|
|
|
|
// within the current Organization
|
2017-10-24 17:29:46 +00:00
|
|
|
u.Roles = append(roles, usr.Roles...)
|
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
return s.store.Update(ctx, u)
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// All returns all users
|
2017-10-30 18:31:19 +00:00
|
|
|
func (s *UsersStore) All(ctx context.Context) ([]chronograf.User, error) {
|
2017-10-31 21:40:58 +00:00
|
|
|
err := validOrganization(ctx)
|
2017-10-24 20:53:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-10-24 17:29:46 +00:00
|
|
|
}
|
2017-10-31 21:40:58 +00:00
|
|
|
|
2017-10-30 18:31:19 +00:00
|
|
|
usrs, err := s.store.All(ctx)
|
2017-10-24 17:29:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Filtering users that have no associtation to an organization
|
|
|
|
us := usrs[:0]
|
|
|
|
for _, usr := range usrs {
|
|
|
|
roles := usr.Roles[:0]
|
|
|
|
for _, r := range usr.Roles {
|
2017-10-31 21:40:58 +00:00
|
|
|
if r.Organization == s.organization {
|
2017-10-24 17:29:46 +00:00
|
|
|
roles = append(roles, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(roles) != 0 {
|
|
|
|
// Only add users if they have a role in the associated organization
|
|
|
|
usr.Roles = roles
|
|
|
|
us = append(us, usr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return us, nil
|
|
|
|
}
|