mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-07 04:40:05 -06:00
Merge pull request #3191 from rhafer/graphadmin
Add permission checks to `users` and `groups` Graph API
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