mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-08 13:19:58 -06:00
Add permission checks to users and groups Graph API
Only users with the account management permission should be able to create, update or delete users. This also restricts access to the APIs that allow listing all Groups/all Users. Fixes #3177
This commit is contained in:
53
graph/pkg/middleware/requireadmin.go
Normal file
53
graph/pkg/middleware/requireadmin.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
revactx "github.com/cs3org/reva/pkg/ctx"
|
||||
accounts "github.com/owncloud/ocis/accounts/pkg/service/v0"
|
||||
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
)
|
||||
|
||||
// RequireAdmin middleware is used to require the user in context to be an admin / have account management permissions
|
||||
func RequireAdmin(rm *roles.Manager, logger log.Logger) func(next http.Handler) http.Handler {
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
u, ok := revactx.ContextGetUser(r.Context())
|
||||
if !ok {
|
||||
errorcode.AccessDenied.Render(w, r, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
if u.Id == nil || u.Id.OpaqueId == "" {
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "user is missing an id")
|
||||
return
|
||||
}
|
||||
// get roles from context
|
||||
roleIDs, ok := roles.ReadRoleIDsFromContext(r.Context())
|
||||
if !ok {
|
||||
logger.Debug().Str("userid", u.Id.OpaqueId).Msg("No roles in context, contacting settings service")
|
||||
var err error
|
||||
roleIDs, err = rm.FindRoleIDsForUser(r.Context(), u.Id.OpaqueId)
|
||||
if err != nil {
|
||||
logger.Err(err).Str("userid", u.Id.OpaqueId).Msg("failed to get roles for user")
|
||||
errorcode.AccessDenied.Render(w, r, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
if len(roleIDs) == 0 {
|
||||
errorcode.AccessDenied.Render(w, r, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// check if permission is present in roles of the authenticated account
|
||||
if rm.FindPermissionByID(r.Context(), roleIDs, accounts.AccountManagementPermissionID) != nil {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
errorcode.AccessDenied.Render(w, r, http.StatusUnauthorized, "Unauthorized")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/owncloud/ocis/graph/pkg/config"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
settingssvc "github.com/owncloud/ocis/protogen/gen/ocis/services/settings/v0"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -17,6 +19,8 @@ type Options struct {
|
||||
Middleware []func(http.Handler) http.Handler
|
||||
GatewayClient GatewayClient
|
||||
HTTPClient HTTPClient
|
||||
RoleService settingssvc.RoleService
|
||||
RoleManager *roles.Manager
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
@@ -64,3 +68,17 @@ func WithHTTPClient(val HTTPClient) Option {
|
||||
o.HTTPClient = val
|
||||
}
|
||||
}
|
||||
|
||||
// RoleService provides a function to set the RoleService option.
|
||||
func RoleService(val settingssvc.RoleService) Option {
|
||||
return func(o *Options) {
|
||||
o.RoleService = val
|
||||
}
|
||||
}
|
||||
|
||||
// RoleManager provides a function to set the RoleManager option.
|
||||
func RoleManager(val *roles.Manager) Option {
|
||||
return func(o *Options) {
|
||||
o.RoleManager = val
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ReneKroon/ttlcache/v2"
|
||||
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
|
||||
@@ -12,8 +13,12 @@ import (
|
||||
|
||||
"github.com/owncloud/ocis/graph/pkg/identity"
|
||||
"github.com/owncloud/ocis/graph/pkg/identity/ldap"
|
||||
graphm "github.com/owncloud/ocis/graph/pkg/middleware"
|
||||
"github.com/owncloud/ocis/ocis-pkg/account"
|
||||
opkgm "github.com/owncloud/ocis/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
|
||||
settingssvc "github.com/owncloud/ocis/protogen/gen/ocis/services/settings/v0"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -111,6 +116,23 @@ func NewService(opts ...Option) Service {
|
||||
svc.httpClient = options.HTTPClient
|
||||
}
|
||||
|
||||
roleService := options.RoleService
|
||||
if roleService == nil {
|
||||
roleService = settingssvc.NewRoleService("com.owncloud.api.settings", grpc.DefaultClient)
|
||||
}
|
||||
roleManager := options.RoleManager
|
||||
if roleManager == nil {
|
||||
m := roles.NewManager(
|
||||
roles.CacheSize(1024),
|
||||
roles.CacheTTL(time.Hour),
|
||||
roles.Logger(options.Logger),
|
||||
roles.RoleService(roleService),
|
||||
)
|
||||
roleManager = &m
|
||||
}
|
||||
|
||||
requireAdmin := graphm.RequireAdmin(roleManager, options.Logger)
|
||||
|
||||
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
r.Use(middleware.StripSlashes)
|
||||
r.Route("/v1.0", func(r chi.Router) {
|
||||
@@ -120,25 +142,25 @@ func NewService(opts ...Option) Service {
|
||||
r.Get("/drive/root/children", svc.GetRootDriveChildren)
|
||||
})
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
r.Get("/", svc.GetUsers)
|
||||
r.Post("/", svc.PostUser)
|
||||
r.With(requireAdmin).Get("/", svc.GetUsers)
|
||||
r.With(requireAdmin).Post("/", svc.PostUser)
|
||||
r.Route("/{userID}", func(r chi.Router) {
|
||||
r.Get("/", svc.GetUser)
|
||||
r.Delete("/", svc.DeleteUser)
|
||||
r.Patch("/", svc.PatchUser)
|
||||
r.With(requireAdmin).Delete("/", svc.DeleteUser)
|
||||
r.With(requireAdmin).Patch("/", svc.PatchUser)
|
||||
})
|
||||
})
|
||||
r.Route("/groups", func(r chi.Router) {
|
||||
r.Get("/", svc.GetGroups)
|
||||
r.Post("/", svc.PostGroup)
|
||||
r.With(requireAdmin).Get("/", svc.GetGroups)
|
||||
r.With(requireAdmin).Post("/", svc.PostGroup)
|
||||
r.Route("/{groupID}", func(r chi.Router) {
|
||||
r.Get("/", svc.GetGroup)
|
||||
r.Delete("/", svc.DeleteGroup)
|
||||
r.Patch("/", svc.PatchGroup)
|
||||
r.With(requireAdmin).Delete("/", svc.DeleteGroup)
|
||||
r.With(requireAdmin).Patch("/", svc.PatchGroup)
|
||||
r.Route("/members", func(r chi.Router) {
|
||||
r.Get("/", svc.GetGroupMembers)
|
||||
r.Post("/$ref", svc.PostGroupMember)
|
||||
r.Delete("/{memberID}/$ref", svc.DeleteGroupMember)
|
||||
r.With(requireAdmin).Get("/", svc.GetGroupMembers)
|
||||
r.With(requireAdmin).Post("/$ref", svc.PostGroupMember)
|
||||
r.With(requireAdmin).Delete("/{memberID}/$ref", svc.DeleteGroupMember)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user