Add option to specify users are create as super admin
parent
0ba2b40abe
commit
4e51963399
|
@ -268,7 +268,8 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
|
||||||
Organization: fmt.Sprintf("%d", defaultOrg.ID),
|
Organization: fmt.Sprintf("%d", defaultOrg.ID),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
SuperAdmin: s.firstUser(),
|
// TODO(desa): this needs a better name
|
||||||
|
SuperAdmin: s.newUsersAreSuperAdmin(),
|
||||||
}
|
}
|
||||||
|
|
||||||
newUser, err := s.Store.Users(serverCtx).Add(serverCtx, user)
|
newUser, err := s.Store.Users(serverCtx).Add(serverCtx, user)
|
||||||
|
@ -299,7 +300,6 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
|
||||||
encodeJSON(w, http.StatusOK, res, s.Logger)
|
encodeJSON(w, http.StatusOK, res, s.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(desa): very slow
|
|
||||||
func (s *Service) firstUser() bool {
|
func (s *Service) firstUser() bool {
|
||||||
serverCtx := serverContext(context.Background())
|
serverCtx := serverContext(context.Background())
|
||||||
users, err := s.Store.Users(serverCtx).All(serverCtx)
|
users, err := s.Store.Users(serverCtx).All(serverCtx)
|
||||||
|
@ -309,6 +309,9 @@ func (s *Service) firstUser() bool {
|
||||||
|
|
||||||
return len(users) == 0
|
return len(users) == 0
|
||||||
}
|
}
|
||||||
|
func (s *Service) newUsersAreSuperAdmin() bool {
|
||||||
|
return !s.NewUsersNotSuperAdmin
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) usersOrganizations(ctx context.Context, u *chronograf.User) ([]chronograf.Organization, error) {
|
func (s *Service) usersOrganizations(ctx context.Context, u *chronograf.User) ([]chronograf.Organization, error) {
|
||||||
if u == nil {
|
if u == nil {
|
||||||
|
|
|
@ -21,10 +21,11 @@ type MockUsers struct{}
|
||||||
|
|
||||||
func TestService_Me(t *testing.T) {
|
func TestService_Me(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
UsersStore chronograf.UsersStore
|
UsersStore chronograf.UsersStore
|
||||||
OrganizationsStore chronograf.OrganizationsStore
|
OrganizationsStore chronograf.OrganizationsStore
|
||||||
Logger chronograf.Logger
|
Logger chronograf.Logger
|
||||||
UseAuth bool
|
UseAuth bool
|
||||||
|
NewUsersNotSuperAdmin bool
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
w *httptest.ResponseRecorder
|
w *httptest.ResponseRecorder
|
||||||
|
@ -46,8 +47,9 @@ func TestService_Me(t *testing.T) {
|
||||||
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
UseAuth: true,
|
UseAuth: true,
|
||||||
Logger: log.New(log.DebugLevel),
|
NewUsersNotSuperAdmin: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
OrganizationsStore: &mocks.OrganizationsStore{
|
OrganizationsStore: &mocks.OrganizationsStore{
|
||||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||||
return &chronograf.Organization{
|
return &chronograf.Organization{
|
||||||
|
@ -142,10 +144,6 @@ func TestService_Me(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
UsersStore: &mocks.UsersStore{
|
UsersStore: &mocks.UsersStore{
|
||||||
AllF: func(ctx context.Context) ([]chronograf.User, error) {
|
|
||||||
// This function gets to verify that there is at least one first user
|
|
||||||
return []chronograf.User{{}}, nil
|
|
||||||
},
|
|
||||||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||||||
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
|
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
|
||||||
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
|
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
|
||||||
|
@ -177,8 +175,9 @@ func TestService_Me(t *testing.T) {
|
||||||
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
UseAuth: true,
|
UseAuth: true,
|
||||||
Logger: log.New(log.DebugLevel),
|
NewUsersNotSuperAdmin: false,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
OrganizationsStore: &mocks.OrganizationsStore{
|
OrganizationsStore: &mocks.OrganizationsStore{
|
||||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||||
return &chronograf.Organization{
|
return &chronograf.Organization{
|
||||||
|
@ -198,10 +197,53 @@ func TestService_Me(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
UsersStore: &mocks.UsersStore{
|
UsersStore: &mocks.UsersStore{
|
||||||
AllF: func(ctx context.Context) ([]chronograf.User, error) {
|
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||||||
// This function gets to verify that there is at least one first user
|
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
|
||||||
return []chronograf.User{{}}, nil
|
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
|
||||||
|
}
|
||||||
|
return nil, chronograf.ErrUserNotFound
|
||||||
},
|
},
|
||||||
|
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{
|
||||||
|
Subject: "secret",
|
||||||
|
Issuer: "auth0",
|
||||||
|
},
|
||||||
|
wantStatus: http.StatusOK,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"name":"secret","superAdmin":true,"roles":[{"name":"member","organization":"0"}],"provider":"auth0","scheme":"oauth2","links":{"self":"/chronograf/v1/users/0"},"organizations":[{"id":"0","name":"The Bad Place"}],"currentOrganization":{"id":"0","name":"The Bad Place"}}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "New user - New users not super admin",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
NewUsersNotSuperAdmin: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
OrganizationsStore: &mocks.OrganizationsStore{
|
||||||
|
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||||
|
return &chronograf.Organization{
|
||||||
|
ID: 0,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||||||
|
return &chronograf.Organization{
|
||||||
|
ID: 0,
|
||||||
|
Name: "The Bad Place",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsersStore: &mocks.UsersStore{
|
||||||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||||||
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
|
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
|
||||||
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
|
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
|
||||||
|
@ -232,7 +274,8 @@ func TestService_Me(t *testing.T) {
|
||||||
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
UseAuth: true,
|
UseAuth: true,
|
||||||
|
NewUsersNotSuperAdmin: true,
|
||||||
OrganizationsStore: &mocks.OrganizationsStore{
|
OrganizationsStore: &mocks.OrganizationsStore{
|
||||||
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
|
||||||
return &chronograf.Organization{
|
return &chronograf.Organization{
|
||||||
|
@ -249,10 +292,6 @@ func TestService_Me(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
UsersStore: &mocks.UsersStore{
|
UsersStore: &mocks.UsersStore{
|
||||||
AllF: func(ctx context.Context) ([]chronograf.User, error) {
|
|
||||||
// This function gets to verify that there is at least one first user
|
|
||||||
return []chronograf.User{{}}, nil
|
|
||||||
},
|
|
||||||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||||||
return nil, chronograf.ErrUserNotFound
|
return nil, chronograf.ErrUserNotFound
|
||||||
},
|
},
|
||||||
|
@ -280,8 +319,9 @@ func TestService_Me(t *testing.T) {
|
||||||
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
UseAuth: false,
|
UseAuth: false,
|
||||||
Logger: log.New(log.DebugLevel),
|
NewUsersNotSuperAdmin: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
},
|
},
|
||||||
wantStatus: http.StatusOK,
|
wantStatus: http.StatusOK,
|
||||||
wantContentType: "application/json",
|
wantContentType: "application/json",
|
||||||
|
@ -295,8 +335,9 @@ func TestService_Me(t *testing.T) {
|
||||||
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
r: httptest.NewRequest("GET", "http://example.com/foo", nil),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
UseAuth: true,
|
UseAuth: true,
|
||||||
Logger: log.New(log.DebugLevel),
|
NewUsersNotSuperAdmin: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
},
|
},
|
||||||
wantStatus: http.StatusUnprocessableEntity,
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
principal: oauth2.Principal{
|
principal: oauth2.Principal{
|
||||||
|
@ -358,8 +399,9 @@ func TestService_Me(t *testing.T) {
|
||||||
UsersStore: tt.fields.UsersStore,
|
UsersStore: tt.fields.UsersStore,
|
||||||
OrganizationsStore: tt.fields.OrganizationsStore,
|
OrganizationsStore: tt.fields.OrganizationsStore,
|
||||||
},
|
},
|
||||||
Logger: tt.fields.Logger,
|
Logger: tt.fields.Logger,
|
||||||
UseAuth: tt.fields.UseAuth,
|
UseAuth: tt.fields.UseAuth,
|
||||||
|
NewUsersNotSuperAdmin: tt.fields.NewUsersNotSuperAdmin,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Me(tt.args.w, tt.args.r)
|
s.Me(tt.args.w, tt.args.r)
|
||||||
|
|
|
@ -57,6 +57,8 @@ type Server struct {
|
||||||
CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts (/usr/share/chronograf/canned)" env:"CANNED_PATH" default:"canned"`
|
CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts (/usr/share/chronograf/canned)" env:"CANNED_PATH" default:"canned"`
|
||||||
TokenSecret string `short:"t" long:"token-secret" description:"Secret to sign tokens" env:"TOKEN_SECRET"`
|
TokenSecret string `short:"t" long:"token-secret" description:"Secret to sign tokens" env:"TOKEN_SECRET"`
|
||||||
AuthDuration time.Duration `long:"auth-duration" default:"720h" description:"Total duration of cookie life for authentication (in hours). 0 means authentication expires on browser close." env:"AUTH_DURATION"`
|
AuthDuration time.Duration `long:"auth-duration" default:"720h" description:"Total duration of cookie life for authentication (in hours). 0 means authentication expires on browser close." env:"AUTH_DURATION"`
|
||||||
|
// TODO(desa): think of a better name
|
||||||
|
NewUsersNotSuperAdmin bool `long:"new-users-not-super-admin" description:"All new users will not be given the Super Admin privilege" env:"NEW_USRES_NOT_SUPER_ADMIN"`
|
||||||
|
|
||||||
GithubClientID string `short:"i" long:"github-client-id" description:"Github Client ID for OAuth 2 support" env:"GH_CLIENT_ID"`
|
GithubClientID string `short:"i" long:"github-client-id" description:"Github Client ID for OAuth 2 support" env:"GH_CLIENT_ID"`
|
||||||
GithubClientSecret string `short:"s" long:"github-client-secret" description:"Github Client Secret for OAuth 2 support" env:"GH_CLIENT_SECRET"`
|
GithubClientSecret string `short:"s" long:"github-client-secret" description:"Github Client Secret for OAuth 2 support" env:"GH_CLIENT_SECRET"`
|
||||||
|
@ -300,6 +302,8 @@ func (s *Server) Serve(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
service := openService(ctx, s.BoltPath, layoutBuilder, sourcesBuilder, kapacitorBuilder, logger, s.useAuth())
|
service := openService(ctx, s.BoltPath, layoutBuilder, sourcesBuilder, kapacitorBuilder, logger, s.useAuth())
|
||||||
|
// TODO(desa): better name
|
||||||
|
service.NewUsersNotSuperAdmin = s.NewUsersNotSuperAdmin
|
||||||
if err := service.HandleNewSources(ctx, s.NewSources); err != nil {
|
if err := service.HandleNewSources(ctx, s.NewSources); err != nil {
|
||||||
logger.
|
logger.
|
||||||
WithField("component", "server").
|
WithField("component", "server").
|
||||||
|
|
|
@ -15,7 +15,9 @@ type Service struct {
|
||||||
TimeSeriesClient TimeSeriesClient
|
TimeSeriesClient TimeSeriesClient
|
||||||
Logger chronograf.Logger
|
Logger chronograf.Logger
|
||||||
UseAuth bool
|
UseAuth bool
|
||||||
Databases chronograf.Databases
|
// TODO(desa): better name
|
||||||
|
NewUsersNotSuperAdmin bool
|
||||||
|
Databases chronograf.Databases
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimeSeriesClient returns the correct client for a time series database.
|
// TimeSeriesClient returns the correct client for a time series database.
|
||||||
|
|
Loading…
Reference in New Issue