actually check permissions to fix tests
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
@@ -16,8 +16,10 @@ import (
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
fieldmask_utils "github.com/mennanov/fieldmask-utils"
|
||||
merrors "github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
|
||||
"github.com/owncloud/ocis/accounts/pkg/storage"
|
||||
"github.com/owncloud/ocis/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
|
||||
settings_svc "github.com/owncloud/ocis/settings/pkg/service/v0"
|
||||
@@ -75,6 +77,22 @@ func (s Service) hasAccountManagementPermissions(ctx context.Context) bool {
|
||||
return s.RoleManager.FindPermissionByID(ctx, roleIDs, AccountManagementPermissionID) != nil
|
||||
}
|
||||
|
||||
func (s Service) hasSelfManagementPermissions(ctx context.Context) bool {
|
||||
// get roles from context
|
||||
roleIDs, ok := roles.ReadRoleIDsFromContext(ctx)
|
||||
if !ok {
|
||||
/**
|
||||
* FIXME: with this we are skipping permission checks on all requests that are coming in without roleIDs in the
|
||||
* metadata context. This is a huge security impairment, as that's the case not only for grpc requests but also
|
||||
* for unauthenticated http requests and http requests coming in without hitting the ocis-proxy first.
|
||||
*/
|
||||
return true
|
||||
}
|
||||
|
||||
// check if permission is present in roles of the authenticated account
|
||||
return s.RoleManager.FindPermissionByID(ctx, roleIDs, SelfManagementPermissionID) != nil
|
||||
}
|
||||
|
||||
// serviceUserToIndex temporarily adds a service user to the index, which is supposed to be removed before the lock on the handler function is released
|
||||
func (s Service) serviceUserToIndex() (teardownServiceUser func()) {
|
||||
if s.Config.ServiceUser.Username != "" && s.Config.ServiceUser.UUID != "" {
|
||||
@@ -105,9 +123,12 @@ func (s Service) getInMemoryServiceUser() proto.Account {
|
||||
// ListAccounts implements the AccountsServiceHandler interface
|
||||
// the query contains account properties
|
||||
func (s Service) ListAccounts(ctx context.Context, in *proto.ListAccountsRequest, out *proto.ListAccountsResponse) (err error) {
|
||||
if !s.hasAccountManagementPermissions(ctx) {
|
||||
hasSelf := s.hasSelfManagementPermissions(ctx)
|
||||
hasManagement := s.hasAccountManagementPermissions(ctx)
|
||||
if !hasSelf && !hasManagement {
|
||||
return merrors.Forbidden(s.id, "no permission for ListAccounts")
|
||||
}
|
||||
onlySelf := hasSelf && !hasManagement
|
||||
|
||||
accLock.Lock()
|
||||
defer accLock.Unlock()
|
||||
@@ -146,6 +167,15 @@ func (s Service) ListAccounts(ctx context.Context, in *proto.ListAccountsRequest
|
||||
return nil
|
||||
}
|
||||
|
||||
if onlySelf {
|
||||
// limit list to own account id
|
||||
if aid, ok := metadata.Get(ctx, middleware.AccountID); ok {
|
||||
in.Query = "id eq '" + aid + "'"
|
||||
} else {
|
||||
return merrors.InternalServerError(s.id, "account id not in context")
|
||||
}
|
||||
}
|
||||
|
||||
if in.Query == "" {
|
||||
err = s.repo.LoadAccounts(ctx, &out.Accounts)
|
||||
if err != nil {
|
||||
@@ -202,9 +232,12 @@ func (s Service) findAccountsByQuery(ctx context.Context, query string) ([]strin
|
||||
|
||||
// GetAccount implements the AccountsServiceHandler interface
|
||||
func (s Service) GetAccount(ctx context.Context, in *proto.GetAccountRequest, out *proto.Account) (err error) {
|
||||
if !s.hasAccountManagementPermissions(ctx) {
|
||||
hasSelf := s.hasSelfManagementPermissions(ctx)
|
||||
hasManagement := s.hasAccountManagementPermissions(ctx)
|
||||
if !hasSelf && !hasManagement {
|
||||
return merrors.Forbidden(s.id, "no permission for GetAccount")
|
||||
}
|
||||
onlySelf := hasSelf && !hasManagement
|
||||
|
||||
accLock.Lock()
|
||||
defer accLock.Unlock()
|
||||
@@ -213,6 +246,17 @@ func (s Service) GetAccount(ctx context.Context, in *proto.GetAccountRequest, ou
|
||||
return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error())
|
||||
}
|
||||
|
||||
if onlySelf {
|
||||
// limit get to own account id
|
||||
if aid, ok := metadata.Get(ctx, middleware.AccountID); ok {
|
||||
if id != aid {
|
||||
return merrors.Forbidden(s.id, "no permission for GetAccount of another user")
|
||||
}
|
||||
} else {
|
||||
return merrors.InternalServerError(s.id, "account id not in context")
|
||||
}
|
||||
}
|
||||
|
||||
if err = s.repo.LoadAccount(ctx, id, out); err != nil {
|
||||
if storage.IsNotFoundErr(err) {
|
||||
return merrors.NotFound(s.id, "account not found: %v", err.Error())
|
||||
|
||||
@@ -11,13 +11,17 @@ import (
|
||||
|
||||
const (
|
||||
// AccountManagementPermissionID is the hardcoded setting UUID for the account management permission
|
||||
AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73"
|
||||
AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73"
|
||||
// AccountManagementPermissionName is the hardcoded setting name for the account management permission
|
||||
AccountManagementPermissionName string = "account-management"
|
||||
// GroupManagementPermissionID is the hardcoded setting UUID for the group management permission
|
||||
GroupManagementPermissionID string = "522adfbe-5908-45b4-b135-41979de73245"
|
||||
GroupManagementPermissionID string = "522adfbe-5908-45b4-b135-41979de73245"
|
||||
// GroupManagementPermissionName is the hardcoded setting name for the group management permission
|
||||
GroupManagementPermissionName string = "group-management"
|
||||
GroupManagementPermissionName string = "group-management"
|
||||
// SelfManagementPermissionID is the hardcoded setting UUID for the self management permission
|
||||
SelfManagementPermissionID string = "e03070e9-4362-4cc6-a872-1c7cb2eb2b8e"
|
||||
// SelfManagementPermissionName is the hardcoded setting name for the self management permission
|
||||
SelfManagementPermissionName string = "self-management"
|
||||
)
|
||||
|
||||
// RegisterPermissions registers permissions for account management and group management with the settings service.
|
||||
@@ -78,5 +82,24 @@ func generateAccountManagementPermissionsRequests() []settings.AddSettingToBundl
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
BundleId: ssvc.BundleUUIDRoleUser,
|
||||
Setting: &settings.Setting{
|
||||
Id: SelfManagementPermissionID,
|
||||
Name: SelfManagementPermissionName,
|
||||
DisplayName: "Self Management",
|
||||
Description: "This permission gives access to self management.",
|
||||
Resource: &settings.Resource{
|
||||
Type: settings.Resource_TYPE_USER,
|
||||
Id: "me",
|
||||
},
|
||||
Value: &settings.Setting_PermissionValue{
|
||||
PermissionValue: &settings.Permission{
|
||||
Operation: settings.Permission_OPERATION_READWRITE,
|
||||
Constraint: settings.Permission_CONSTRAINT_OWN,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzS
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CiscoM31/godata v0.0.0-20201003040028-eadcd34e7f06 h1:FKxVU/j9Dd8Je0YkVkm8Fxpz9zIeN21SEkcbzA6NWgY=
|
||||
github.com/CiscoM31/godata v0.0.0-20201003040028-eadcd34e7f06/go.mod h1:tjaihnMBH6p5DVnGBksDQQHpErbrLvb9ek6cEWuyc7E=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e h1:Bqtt5C+uVk+vH/t5dmB47uDCTwxw16EYHqvJnmY2aQc=
|
||||
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e/go.mod h1:njRCDrl+1RQ/A/+KVU8Ho2EWAxUSkohOWczdW3dzDG0=
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cs3org/reva/pkg/token/manager/jwt"
|
||||
"github.com/cs3org/reva/pkg/user"
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/owncloud/ocis/ocis-pkg/account"
|
||||
)
|
||||
@@ -49,18 +50,21 @@ func ExtractAccountUUID(opts ...account.Option) func(http.Handler) http.Handler
|
||||
return
|
||||
}
|
||||
|
||||
user, err := tokenManager.DismantleToken(r.Context(), token)
|
||||
u, err := tokenManager.DismantleToken(r.Context(), token)
|
||||
if err != nil {
|
||||
opt.Logger.Error().Err(err)
|
||||
return
|
||||
}
|
||||
|
||||
// store user in context for request
|
||||
ctx := user.ContextSetUser(r.Context(), u)
|
||||
|
||||
// Important: user.Id.OpaqueId is the AccountUUID. Set this way in the account uuid middleware in ocis-proxy.
|
||||
// https://github.com/owncloud/ocis-proxy/blob/ea254d6036592cf9469d757d1295e0c4309d1e63/pkg/middleware/account_uuid.go#L109
|
||||
ctx := context.WithValue(r.Context(), UUIDKey, user.Id.OpaqueId)
|
||||
ctx = context.WithValue(ctx, UUIDKey, u.Id.OpaqueId)
|
||||
// TODO: implement token manager in cs3org/reva that uses generic metadata instead of access token from header.
|
||||
ctx = metadata.Set(ctx, AccountID, user.Id.OpaqueId)
|
||||
ctx = metadata.Set(ctx, RoleIDs, string(user.Opaque.Map["roles"].Value))
|
||||
ctx = metadata.Set(ctx, AccountID, u.Id.OpaqueId)
|
||||
ctx = metadata.Set(ctx, RoleIDs, string(u.Opaque.Map["roles"].Value))
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cs3org/reva/pkg/token/manager/jwt"
|
||||
"github.com/cs3org/reva/pkg/user"
|
||||
)
|
||||
|
||||
// AccessToken middleware is used to set the user from an x-access-token to the context
|
||||
func AccessToken(opts ...Option) func(next http.Handler) http.Handler {
|
||||
opt := newOptions(opts...)
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
// TODO: handle error
|
||||
tokenManager, err := jwt.New(map[string]interface{}{
|
||||
"secret": opt.TokenManagerConfig.JWTSecret,
|
||||
"expires": int64(60),
|
||||
})
|
||||
if err != nil {
|
||||
opt.Logger.Fatal().Err(err).Msgf("Could not initialize token-manager")
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.Header.Get("x-access-token")
|
||||
if token != "" {
|
||||
u, err := tokenManager.DismantleToken(r.Context(), token)
|
||||
if err != nil {
|
||||
opt.Logger.Error().Err(err).Msg("could not dismantle token")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// store user in context for request
|
||||
r = r.WithContext(user.ContextSetUser(r.Context(), u))
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/owncloud/ocis/ocs/pkg/config"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -12,8 +12,8 @@ type Option func(o *Options)
|
||||
type Options struct {
|
||||
// Logger to use for logging, must be set
|
||||
Logger log.Logger
|
||||
// TokenManagerConfig for communicating with the reva token manager
|
||||
TokenManagerConfig config.TokenManager
|
||||
// RoleManager for looking up permissions
|
||||
RoleManager *roles.Manager
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
@@ -34,9 +34,9 @@ func Logger(l log.Logger) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// TokenManagerConfig provides a function to set the token manger config option.
|
||||
func TokenManagerConfig(cfg config.TokenManager) Option {
|
||||
// RoleManager provides a function to set the RoleManager option.
|
||||
func RoleManager(val *roles.Manager) Option {
|
||||
return func(o *Options) {
|
||||
o.TokenManagerConfig = cfg
|
||||
o.RoleManager = val
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
accounts "github.com/owncloud/ocis/accounts/pkg/service/v0"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
"github.com/owncloud/ocis/ocs/pkg/service/v0/data"
|
||||
"github.com/owncloud/ocis/ocs/pkg/service/v0/response"
|
||||
)
|
||||
|
||||
// RequireAdmin middleware is used to require the user in context to be an admin / have account management permissions
|
||||
func RequireAdmin(opts ...Option) func(next http.Handler) http.Handler {
|
||||
opt := newOptions(opts...)
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// get roles from context
|
||||
roleIDs, ok := roles.ReadRoleIDsFromContext(r.Context())
|
||||
if !ok {
|
||||
render.Render(w, r, response.ErrRender(data.MetaUnauthorized.StatusCode, "Unauthorized"))
|
||||
return
|
||||
}
|
||||
|
||||
// check if permission is present in roles of the authenticated account
|
||||
if opt.RoleManager.FindPermissionByID(r.Context(), roleIDs, accounts.AccountManagementPermissionID) != nil {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
render.Render(w, r, response.ErrRender(data.MetaUnauthorized.StatusCode, "Unauthorized"))
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cs3org/reva/pkg/user"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/render"
|
||||
accounts "github.com/owncloud/ocis/accounts/pkg/service/v0"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
"github.com/owncloud/ocis/ocs/pkg/service/v0/data"
|
||||
"github.com/owncloud/ocis/ocs/pkg/service/v0/response"
|
||||
)
|
||||
|
||||
// RequireSelfOrAdmin middleware is used to require the requesting user to be an admin or the requested user himself
|
||||
func RequireSelfOrAdmin(opts ...Option) func(next http.Handler) http.Handler {
|
||||
opt := newOptions(opts...)
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
u, ok := user.ContextGetUser(r.Context())
|
||||
if !ok {
|
||||
render.Render(w, r, response.ErrRender(data.MetaUnauthorized.StatusCode, "Unauthorized"))
|
||||
return
|
||||
}
|
||||
if u.Id == nil || u.Id.OpaqueId == "" {
|
||||
render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "user is missing an id"))
|
||||
return
|
||||
}
|
||||
// get roles from context
|
||||
roleIDs, ok := roles.ReadRoleIDsFromContext(r.Context())
|
||||
if !ok {
|
||||
render.Render(w, r, response.ErrRender(data.MetaUnauthorized.StatusCode, "Unauthorized"))
|
||||
return
|
||||
}
|
||||
|
||||
// check if account management permission is present in roles of the authenticated account
|
||||
if opt.RoleManager.FindPermissionByID(r.Context(), roleIDs, accounts.AccountManagementPermissionID) != nil {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// check if self management permission is present in roles of the authenticated account
|
||||
if opt.RoleManager.FindPermissionByID(r.Context(), roleIDs, accounts.SelfManagementPermissionID) != nil {
|
||||
userid := chi.URLParam(r, "userid")
|
||||
if userid == "" || userid == u.Id.OpaqueId || userid == u.Username {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
render.Render(w, r, response.ErrRender(data.MetaUnauthorized.StatusCode, "Unauthorized"))
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,10 @@ package svc
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis/ocs/pkg/config"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
"github.com/owncloud/ocis/ocs/pkg/config"
|
||||
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -12,9 +14,11 @@ type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
Middleware []func(http.Handler) http.Handler
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
Middleware []func(http.Handler) http.Handler
|
||||
RoleService settings.RoleService
|
||||
RoleManager *roles.Manager
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
@@ -48,3 +52,17 @@ func Middleware(val ...func(http.Handler) http.Handler) Option {
|
||||
o.Middleware = val
|
||||
}
|
||||
}
|
||||
|
||||
// RoleService provides a function to set the RoleService option.
|
||||
func RoleService(val settings.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,24 @@ package svc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/micro/go-micro/v2/client/grpc"
|
||||
|
||||
mclient "github.com/micro/go-micro/v2/client"
|
||||
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
|
||||
"github.com/owncloud/ocis/ocis-pkg/account"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
opkgm "github.com/owncloud/ocis/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
"github.com/owncloud/ocis/ocs/pkg/config"
|
||||
ocsm "github.com/owncloud/ocis/ocs/pkg/middleware"
|
||||
"github.com/owncloud/ocis/ocs/pkg/service/v0/data"
|
||||
"github.com/owncloud/ocis/ocs/pkg/service/v0/response"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
|
||||
)
|
||||
|
||||
var defaultClient = grpc.NewClient()
|
||||
@@ -31,19 +37,45 @@ func NewService(opts ...Option) Service {
|
||||
m := chi.NewMux()
|
||||
m.Use(options.Middleware...)
|
||||
|
||||
svc := Ocs{
|
||||
config: options.Config,
|
||||
mux: m,
|
||||
logger: options.Logger,
|
||||
roleService := options.RoleService
|
||||
if roleService == nil {
|
||||
// https://github.com/owncloud/ocis-proxy/issues/38
|
||||
// TODO this won't work with a registry other than mdns. Look into Micro's client initialization.
|
||||
roleService = settings.NewRoleService("com.owncloud.api.settings", mclient.DefaultClient)
|
||||
}
|
||||
roleManager := options.RoleManager
|
||||
if roleManager == nil {
|
||||
m := roles.NewManager(
|
||||
roles.CacheSize(1024),
|
||||
roles.CacheTTL(time.Hour*24*7),
|
||||
roles.Logger(options.Logger),
|
||||
roles.RoleService(roleService),
|
||||
)
|
||||
roleManager = &m
|
||||
}
|
||||
|
||||
svc := Ocs{
|
||||
config: options.Config,
|
||||
mux: m,
|
||||
RoleManager: roleManager,
|
||||
logger: options.Logger,
|
||||
}
|
||||
|
||||
requireAdmin := ocsm.RequireAdmin(
|
||||
ocsm.RoleManager(roleManager),
|
||||
)
|
||||
|
||||
requireSelfOrAdmin := ocsm.RequireSelfOrAdmin(
|
||||
ocsm.RoleManager(roleManager),
|
||||
ocsm.Logger(options.Logger),
|
||||
)
|
||||
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
r.NotFound(svc.NotFound)
|
||||
r.Use(middleware.StripSlashes)
|
||||
r.Use(ocsm.AccessToken(
|
||||
ocsm.Logger(options.Logger),
|
||||
ocsm.TokenManagerConfig(options.Config.TokenManager),
|
||||
))
|
||||
r.Use(opkgm.ExtractAccountUUID(
|
||||
account.Logger(options.Logger),
|
||||
account.JWTSecret(options.Config.TokenManager.JWTSecret)),
|
||||
)
|
||||
r.Use(ocsm.OCSFormatCtx) // updates request Accept header according to format=(json|xml) query parameter
|
||||
r.Route("/v{version:(1|2)}.php", func(r chi.Router) {
|
||||
r.Use(response.VersionCtx) // stores version in context
|
||||
@@ -51,28 +83,31 @@ func NewService(opts ...Option) Service {
|
||||
r.Route("/apps/notifications/api/v1", func(r chi.Router) {})
|
||||
r.Route("/cloud", func(r chi.Router) {
|
||||
r.Route("/capabilities", func(r chi.Router) {})
|
||||
// TODO /apps
|
||||
r.Route("/user", func(r chi.Router) {
|
||||
r.Get("/", svc.GetUser)
|
||||
r.With(requireSelfOrAdmin).Get("/", svc.GetSelf)
|
||||
r.Get("/signing-key", svc.GetSigningKey)
|
||||
})
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
r.Get("/", svc.ListUsers)
|
||||
r.Post("/", svc.AddUser)
|
||||
r.Get("/{userid}", svc.GetUser)
|
||||
r.Put("/{userid}", svc.EditUser)
|
||||
r.Delete("/{userid}", svc.DeleteUser)
|
||||
r.With(requireAdmin).Get("/", svc.ListUsers)
|
||||
r.With(requireAdmin).Post("/", svc.AddUser)
|
||||
r.Route("/{userid}", func(r chi.Router) {
|
||||
r.With(requireSelfOrAdmin).Get("/", svc.GetUser)
|
||||
r.With(requireSelfOrAdmin).Put("/", svc.EditUser)
|
||||
r.With(requireAdmin).Delete("/", svc.DeleteUser)
|
||||
})
|
||||
|
||||
r.Route("/{userid}/groups", func(r chi.Router) {
|
||||
r.Get("/", svc.ListUserGroups)
|
||||
r.Post("/", svc.AddToGroup)
|
||||
r.Delete("/", svc.RemoveFromGroup)
|
||||
r.With(requireSelfOrAdmin).Get("/", svc.ListUserGroups)
|
||||
r.With(requireAdmin).Post("/", svc.AddToGroup)
|
||||
r.With(requireAdmin).Delete("/", svc.RemoveFromGroup)
|
||||
})
|
||||
})
|
||||
r.Route("/groups", func(r chi.Router) {
|
||||
r.Get("/", svc.ListGroups)
|
||||
r.Post("/", svc.AddGroup)
|
||||
r.Delete("/{groupid}", svc.DeleteGroup)
|
||||
r.Get("/{groupid}", svc.GetGroupMembers)
|
||||
r.With(requireAdmin).Get("/", svc.ListGroups)
|
||||
r.With(requireAdmin).Post("/", svc.AddGroup)
|
||||
r.With(requireAdmin).Delete("/{groupid}", svc.DeleteGroup)
|
||||
r.With(requireSelfOrAdmin).Get("/{groupid}", svc.GetGroupMembers)
|
||||
})
|
||||
})
|
||||
r.Route("/config", func(r chi.Router) {
|
||||
@@ -86,9 +121,11 @@ func NewService(opts ...Option) Service {
|
||||
|
||||
// Ocs defines implements the business logic for Service.
|
||||
type Ocs struct {
|
||||
config *config.Config
|
||||
logger log.Logger
|
||||
mux *chi.Mux
|
||||
config *config.Config
|
||||
logger log.Logger
|
||||
RoleService settings.RoleService
|
||||
RoleManager *roles.Manager
|
||||
mux *chi.Mux
|
||||
}
|
||||
|
||||
// ServeHTTP implements the Service interface.
|
||||
|
||||
+48
-15
@@ -22,22 +22,58 @@ import (
|
||||
storepb "github.com/owncloud/ocis/store/pkg/proto/v0"
|
||||
)
|
||||
|
||||
// GetUser returns the currently logged in user
|
||||
// GetSelf returns the currently logged in user
|
||||
func (o Ocs) GetSelf(w http.ResponseWriter, r *http.Request) {
|
||||
var account *accounts.Account
|
||||
var err error
|
||||
u, ok := user.ContextGetUser(r.Context())
|
||||
if !ok || u.Id == nil || u.Id.OpaqueId == "" {
|
||||
render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "user is missing an id"))
|
||||
return
|
||||
}
|
||||
|
||||
account, err = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
|
||||
Id: u.Id.OpaqueId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
merr := merrors.FromError(err)
|
||||
if merr.Code == http.StatusNotFound {
|
||||
// if the user was authenticated why wes he not found?!? log error?
|
||||
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
|
||||
} else {
|
||||
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
|
||||
}
|
||||
o.logger.Error().Err(merr).Interface("user", u).Msg("could not get account for user")
|
||||
return
|
||||
}
|
||||
|
||||
// remove password from log if it is set
|
||||
if account.PasswordProfile != nil {
|
||||
account.PasswordProfile.Password = ""
|
||||
}
|
||||
o.logger.Debug().Interface("account", account).Msg("got user")
|
||||
|
||||
d := &data.User{
|
||||
UserID: account.PreferredName,
|
||||
DisplayName: account.DisplayName,
|
||||
LegacyDisplayName: account.DisplayName,
|
||||
Email: account.Mail,
|
||||
UIDNumber: account.UidNumber,
|
||||
GIDNumber: account.GidNumber,
|
||||
// TODO hide enabled flag or it might get rendered as false
|
||||
}
|
||||
render.Render(w, r, response.DataRender(d))
|
||||
}
|
||||
|
||||
// GetUser returns the user with the given userid
|
||||
func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO this endpoint needs authentication using the roles and permissions
|
||||
userid := chi.URLParam(r, "userid")
|
||||
var account *accounts.Account
|
||||
var err error
|
||||
|
||||
if userid == "" {
|
||||
u, ok := user.ContextGetUser(r.Context())
|
||||
if !ok || u.Id == nil || u.Id.OpaqueId == "" {
|
||||
render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "missing user in context"))
|
||||
return
|
||||
}
|
||||
account, err = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
|
||||
Id: u.Id.OpaqueId,
|
||||
})
|
||||
render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "missing user in context"))
|
||||
} else {
|
||||
account, err = o.fetchAccountByUsername(r.Context(), userid)
|
||||
}
|
||||
@@ -48,7 +84,7 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
} else {
|
||||
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
|
||||
}
|
||||
o.logger.Error().Err(err).Str("userid", userid).Msg("could not get user")
|
||||
o.logger.Error().Err(merr).Str("userid", userid).Msg("could not get account for user")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -73,8 +109,7 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
Email: account.Mail,
|
||||
UIDNumber: account.UidNumber,
|
||||
GIDNumber: account.GidNumber,
|
||||
Enabled: enabled,
|
||||
// FIXME onlyfor users/{userid} endpoint (not /user)
|
||||
Enabled: enabled, // TODO include in response only when admin?
|
||||
// TODO query storage registry for free space? of home storage, maybe...
|
||||
Quota: &data.Quota{
|
||||
Free: 2840756224000,
|
||||
@@ -89,7 +124,6 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// AddUser creates a new user account
|
||||
func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO this endpoint needs authentication using the roles and permissions
|
||||
userid := r.PostFormValue("userid")
|
||||
password := r.PostFormValue("password")
|
||||
displayname := r.PostFormValue("displayname")
|
||||
@@ -186,7 +220,6 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// EditUser creates a new user account
|
||||
func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO this endpoint needs authentication
|
||||
userid := chi.URLParam(r, "userid")
|
||||
account, err := o.fetchAccountByUsername(r.Context(), userid)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user