From 708c37dc678dc454ff9b9b9396d82c585779a197 Mon Sep 17 00:00:00 2001 From: Michael Desa Date: Tue, 31 Oct 2017 20:58:40 -0400 Subject: [PATCH] WIP cleanup --- bolt/client.go | 3 +++ bolt/organizations.go | 17 +++++++++++++++++ oauth2/jwt.go | 6 ++++++ server/auth.go | 14 ++++++++------ server/dashboards.go | 4 +--- server/kapacitors.go | 2 +- server/layout.go | 4 +--- server/me.go | 20 +++----------------- server/mux.go | 27 ++++++++++++++++----------- server/sources.go | 4 +--- server/users.go | 32 +++++++++++++++++--------------- 11 files changed, 74 insertions(+), 59 deletions(-) diff --git a/bolt/client.go b/bolt/client.go index 42e6cc23bf..ee347461a8 100644 --- a/bolt/client.go +++ b/bolt/client.go @@ -86,6 +86,9 @@ func (c *Client) Open(ctx context.Context) error { if err := c.DashboardsStore.Migrate(ctx); err != nil { return err } + if err := c.OrganizationsStore.Migrate(ctx); err != nil { + return err + } // TODO: this will have to change, and is temporary if err := c.UsersStore.Migrate(ctx); err != nil { return err diff --git a/bolt/organizations.go b/bolt/organizations.go index 264a25430d..339e767dca 100644 --- a/bolt/organizations.go +++ b/bolt/organizations.go @@ -20,6 +20,23 @@ type OrganizationsStore struct { client *Client } +func (s *OrganizationsStore) Migrate(ctx context.Context) error { + o := chronograf.Organization{ + ID: 0, + Name: "__default", + } + return s.client.db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket(OrganizationsBucket) + if v, err := internal.MarshalOrganization(&o); err != nil { + return err + } else if err := b.Put(u64tob(o.ID), v); err != nil { + return err + } + + return nil + }) +} + func (s *OrganizationsStore) Add(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) { if err := s.client.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(OrganizationsBucket) diff --git a/oauth2/jwt.go b/oauth2/jwt.go index 117a648b37..85e8d766c7 100644 --- a/oauth2/jwt.go +++ b/oauth2/jwt.go @@ -93,6 +93,12 @@ func (j *JWT) ValidClaims(jwtToken Token, lifespan time.Duration, alg gojwt.Keyf return Principal{}, fmt.Errorf("claims duration is different from auth lifespan") } + if claims.Organization == "" { + // TODO(desa): this okay? + // Set to be the default organization + claims.Organization = "0" + } + return Principal{ Subject: claims.Subject, Issuer: claims.Issuer, diff --git a/server/auth.go b/server/auth.go index 934f09bcac..0ff1235678 100644 --- a/server/auth.go +++ b/server/auth.go @@ -2,6 +2,7 @@ package server import ( "context" + "fmt" "net/http" "strconv" @@ -86,12 +87,9 @@ func AuthorizedUser( } if p.Organization == "" { - // TODO: remove - p.Organization = "1" - // log.Error("Failed to retrieve organization from principal") - // Error(w, http.StatusUnauthorized, "User is not authorized", logger) - // return + p.Organization = "0" } + // validate that the organization exists orgID, err := strconv.ParseUint(p.Organization, 10, 64) if err != nil { @@ -101,7 +99,7 @@ func AuthorizedUser( } _, err = store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &orgID}) if err != nil { - log.Error("Failed to retrieve organization from organizations store") + log.Error(fmt.Sprintf("Failed to retrieve organization %d from organizations store", orgID)) Error(w, http.StatusUnauthorized, "User is not authorized", logger) return } @@ -177,6 +175,10 @@ func hasAuthorizedRole(u *chronograf.User, role string) bool { return true } } + case SuperAdminRoleName: + // SuperAdmins should have been authorized before this. + // This is only meant to restrict access for non-superadmins. + return false } return false diff --git a/server/dashboards.go b/server/dashboards.go index 9455615e0f..4121de6d08 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -220,9 +220,7 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) { // ValidDashboardRequest verifies that the dashboard cells have a query func ValidDashboardRequest(d *chronograf.Dashboard) error { if d.Organization == "" { - //TODO: Remove this - d.Organization = "1" - //return fmt.Errorf("organization required") + d.Organization = "0" } for i, c := range d.Cells { if err := ValidDashboardCellRequest(&c); err != nil { diff --git a/server/kapacitors.go b/server/kapacitors.go index 0a61cd739b..c72dcd3395 100644 --- a/server/kapacitors.go +++ b/server/kapacitors.go @@ -26,7 +26,7 @@ func (p *postKapacitorRequest) Valid() error { } if p.Organization == "" { - return fmt.Errorf("organization must be set") + p.Organization = "0" } url, err := url.ParseRequestURI(*p.URL) diff --git a/server/layout.go b/server/layout.go index b3fbf91df8..0e55af4318 100644 --- a/server/layout.go +++ b/server/layout.go @@ -191,9 +191,7 @@ func ValidLayoutRequest(l chronograf.Layout) error { } if l.Organization == "" { - //TODO: Remove this - l.Organization = "1" - //return fmt.Errorf("organization required") + l.Organization = "0" } for _, c := range l.Cells { diff --git a/server/me.go b/server/me.go index 5ea59c5310..767be2c5ee 100644 --- a/server/me.go +++ b/server/me.go @@ -208,21 +208,6 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) { return } - // Create default org if no organization exists - // TODO: cleanup - defaultOrgID := uint64(1) - org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ - ID: &defaultOrgID, - }) - - // Create defaultOrg - if err == chronograf.ErrOrganizationNotFound { - // TODO: check err - org, _ = s.Store.Organizations(ctx).Add(ctx, &chronograf.Organization{ - Name: "__default", - }) - } - // Because we didnt find a user, making a new one user := &chronograf.User{ Name: p.Subject, @@ -234,8 +219,9 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) { // TODO: this should be member Roles: []chronograf.Role{ { - Name: ViewerRoleName, - Organization: fmt.Sprintf("%d", org.ID), + Name: ViewerRoleName, + // This is the ID of the default organization + Organization: "0", }, }, // TODO: is super admin for now diff --git a/server/mux.go b/server/mux.go index 7b3fb13773..84f3cb3654 100644 --- a/server/mux.go +++ b/server/mux.go @@ -94,6 +94,15 @@ func NewMux(opts MuxOpts, service Service) http.Handler { next, ) } + EnsureSuperAdmin := func(next http.HandlerFunc) http.HandlerFunc { + return AuthorizedUser( + service.Store, + opts.UseAuth, + SuperAdminRoleName, + opts.Logger, + next, + ) + } /* Documentation */ router.GET("/swagger.json", Spec()) @@ -101,17 +110,12 @@ func NewMux(opts MuxOpts, service Service) http.Handler { /* API */ // Organizations - // TODO: Change to SuperAdmin - router.GET("/chronograf/v1/organizations", EnsureAdmin(service.Organizations)) - // TODO: Change to SuperAdmin - router.POST("/chronograf/v1/organizations", EnsureAdmin(service.NewOrganization)) + router.GET("/chronograf/v1/organizations", EnsureSuperAdmin(service.Organizations)) + router.POST("/chronograf/v1/organizations", EnsureSuperAdmin(service.NewOrganization)) - // TODO: Change to SuperAdmin - router.GET("/chronograf/v1/organizations/:id", EnsureAdmin(service.OrganizationID)) - // TODO: Change to SuperAdmin - router.PATCH("/chronograf/v1/organizations/:id", EnsureAdmin(service.UpdateOrganization)) - // TODO: Change to SuperAdmin - router.DELETE("/chronograf/v1/organizations/:id", EnsureAdmin(service.RemoveOrganization)) + router.GET("/chronograf/v1/organizations/:id", EnsureSuperAdmin(service.OrganizationID)) + router.PATCH("/chronograf/v1/organizations/:id", EnsureSuperAdmin(service.UpdateOrganization)) + router.DELETE("/chronograf/v1/organizations/:id", EnsureSuperAdmin(service.RemoveOrganization)) // Sources router.GET("/chronograf/v1/sources", EnsureViewer(service.Sources)) @@ -193,8 +197,9 @@ func NewMux(opts MuxOpts, service Service) http.Handler { router.GET("/chronograf/v1/me", service.Me) // Set current chronograf organization the user is logged into - router.PUT("/chronograf/v1/me/organization", service.MeOrganization(opts.Auth)) + router.PUT("/chronograf/v1/me", service.MeOrganization(opts.Auth)) + // TODO(desa): what to do about admin's being able to set superadmin router.GET("/chronograf/v1/users", EnsureAdmin(service.Users)) router.POST("/chronograf/v1/users", EnsureAdmin(service.NewUser)) diff --git a/server/sources.go b/server/sources.go index 6784b918d9..283121c795 100644 --- a/server/sources.go +++ b/server/sources.go @@ -288,9 +288,7 @@ func ValidSourceRequest(s chronograf.Source) error { } if s.Organization == "" { - //TODO: Remove this - s.Organization = "1" - //return fmt.Errorf("organization required") + s.Organization = "0" } url, err := url.ParseRequestURI(s.URL) diff --git a/server/users.go b/server/users.go index cbffe1d168..83efe74daa 100644 --- a/server/users.go +++ b/server/users.go @@ -12,11 +12,12 @@ import ( ) type userRequest struct { - ID uint64 `json:"id,string"` - Name string `json:"name"` - Provider string `json:"provider"` - Scheme string `json:"scheme"` - Roles []chronograf.Role `json:"roles"` + ID uint64 `json:"id,string"` + Name string `json:"name"` + Provider string `json:"provider"` + Scheme string `json:"scheme"` + SuperAdmin bool `json:"superAdmin"` + Roles []chronograf.Role `json:"roles"` } func (r *userRequest) ValidCreate() error { @@ -57,7 +58,6 @@ func (r *userRequest) ValidRoles() error { if len(r.Roles) > 0 { for _, r := range r.Roles { switch r.Name { - // TODO: add SuperAdmin case ViewerRoleName, EditorRoleName, AdminRoleName: continue default: @@ -69,12 +69,13 @@ func (r *userRequest) ValidRoles() error { } type userResponse struct { - Links selfLinks `json:"links"` - ID uint64 `json:"id,string"` - Name string `json:"name"` - Provider string `json:"provider"` - Scheme string `json:"scheme"` - Roles []chronograf.Role `json:"roles"` + Links selfLinks `json:"links"` + ID uint64 `json:"id,string"` + Name string `json:"name"` + Provider string `json:"provider"` + Scheme string `json:"scheme"` + SuperAdmin bool `json:"superAdmin"` + Roles []chronograf.Role `json:"roles"` } func newUserResponse(u *chronograf.User) *userResponse { @@ -119,9 +120,10 @@ func newUsersResponse(users []chronograf.User) *usersResponse { // Chronograf User Roles const ( - ViewerRoleName = "viewer" - EditorRoleName = "editor" - AdminRoleName = "admin" + ViewerRoleName = "viewer" + EditorRoleName = "editor" + AdminRoleName = "admin" + SuperAdminRoleName = "superadmin" ) var (