Grant user role in default org if added via API

When users are created via the API they are only given roles in orgs
that are explicitly set. Additionally the roles must be roles that
belong to the current organization (unless they are a super admin).

This leads to a situation where a user may not be a part of the default
organization. If this is the case, we detect it when the user hits /me
and add the user to the default org.
pull/2220/head
Michael Desa 2017-11-02 19:13:51 -04:00
parent 45f1410fd6
commit 3ddd253d68
2 changed files with 54 additions and 4 deletions

View File

@ -197,6 +197,20 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
unknownErrorWithMessage(w, err, s.Logger)
return
}
// If a user was added via the API, they might not yet be a member of the default organization
// Here we check to verify that they are a user in the default organization
// TODO(desa): when https://github.com/influxdata/chronograf/pull/2219 is merge, refactor this to use
// the default organization logic rather than hard coding valies here.
if !hasRoleInDefaultOrganization(usr) {
usr.Roles = append(usr.Roles, chronograf.Role{
Organization: "0",
Name: MemberRoleName,
})
if err := s.Store.Users(ctx).Update(ctx, usr); err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
}
res := newMeResponse(usr)
res.Organizations = orgs
res.CurrentOrganization = currentOrg
@ -284,3 +298,15 @@ func (s *Service) usersOrganizations(ctx context.Context, u *chronograf.User) ([
return orgs, nil
}
// TODO(desa): when https://github.com/influxdata/chronograf/pull/2219 is merge, refactor this to use
// the default organization logic rather than hard coding valies here.
func hasRoleInDefaultOrganization(u *chronograf.User) bool {
for _, role := range u.Roles {
if role.Organization == "0" {
return true
}
}
return false
}

View File

@ -70,6 +70,9 @@ func TestService_Me(t *testing.T) {
Scheme: "oauth2",
}, nil
},
UpdateF: func(ctx context.Context, u *chronograf.User) error {
return nil
},
},
},
principal: oauth2.Principal{
@ -78,7 +81,7 @@ func TestService_Me(t *testing.T) {
},
wantStatus: http.StatusOK,
wantContentType: "application/json",
wantBody: `{"name":"me","provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/0"},"currentOrganization":{"id":"0","name":"The Bad Place"}}
wantBody: `{"name":"me","provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/0"},"currentOrganization":{"id":"0","name":"The Bad Place"},"roles":[{"name":"member","organization":"0"}]}
`,
},
{
@ -112,6 +115,9 @@ func TestService_Me(t *testing.T) {
AddF: func(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
return u, nil
},
UpdateF: func(ctx context.Context, u *chronograf.User) error {
return nil
},
},
},
principal: oauth2.Principal{
@ -150,6 +156,9 @@ func TestService_Me(t *testing.T) {
AddF: func(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
return nil, fmt.Errorf("Why Heavy?")
},
UpdateF: func(ctx context.Context, u *chronograf.User) error {
return nil
},
},
Logger: log.New(log.DebugLevel),
},
@ -216,7 +225,10 @@ func TestService_Me(t *testing.T) {
if tt.wantContentType != "" && content != tt.wantContentType {
t.Errorf("%q. Me() = %v, want %v", tt.name, content, tt.wantContentType)
}
if tt.wantBody != "" && string(body) != tt.wantBody {
if tt.wantBody == "" {
continue
}
if eq, err := jsonEqual(tt.wantBody, string(body)); err != nil || !eq {
t.Errorf("%q. Me() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
}
}
@ -274,6 +286,9 @@ func TestService_MeOrganizations(t *testing.T) {
},
}, nil
},
UpdateF: func(ctx context.Context, u *chronograf.User) error {
return nil
},
},
OrganizationsStore: &mocks.OrganizationsStore{
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
@ -293,7 +308,7 @@ func TestService_MeOrganizations(t *testing.T) {
},
wantStatus: http.StatusOK,
wantContentType: "application/json",
wantBody: `{"name":"me","roles":[{"name":"admin","organization":"1337"}],"provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/0"},"organizations":[{"id":"1337","name":"The ShillBillThrilliettas"}],"currentOrganization":{"id":"1337","name":"The ShillBillThrilliettas"}}`,
wantBody: `{"name":"me","roles":[{"name":"admin","organization":"1337"},{"name":"member","organization":"0"}],"provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/0"},"organizations":[{"id":"1337","name":"The ShillBillThrilliettas"}],"currentOrganization":{"id":"1337","name":"The ShillBillThrilliettas"}}`,
},
{
name: "Change the current User's organization",
@ -325,6 +340,9 @@ func TestService_MeOrganizations(t *testing.T) {
},
}, nil
},
UpdateF: func(ctx context.Context, u *chronograf.User) error {
return nil
},
},
OrganizationsStore: &mocks.OrganizationsStore{
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
@ -345,7 +363,7 @@ func TestService_MeOrganizations(t *testing.T) {
},
wantStatus: http.StatusOK,
wantContentType: "application/json",
wantBody: `{"name":"me","roles":[{"name":"admin","organization":"1337"}],"provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/0"},"organizations":[{"id":"1337","name":"The ThrillShilliettos"}],"currentOrganization":{"id":"1337","name":"The ThrillShilliettos"}}
wantBody: `{"name":"me","roles":[{"name":"admin","organization":"1337"},{"name":"member","organization":"0"}],"provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/0"},"organizations":[{"id":"1337","name":"The ThrillShilliettos"}],"currentOrganization":{"id":"1337","name":"The ThrillShilliettos"}}
`,
},
{
@ -368,6 +386,9 @@ func TestService_MeOrganizations(t *testing.T) {
}
return nil, chronograf.ErrUserNotFound
},
UpdateF: func(ctx context.Context, u *chronograf.User) error {
return nil
},
},
OrganizationsStore: &mocks.OrganizationsStore{
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
@ -420,6 +441,9 @@ func TestService_MeOrganizations(t *testing.T) {
},
}, nil
},
UpdateF: func(ctx context.Context, u *chronograf.User) error {
return nil
},
},
OrganizationsStore: &mocks.OrganizationsStore{
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {