Merge pull request #1962 from owncloud/ocis-1798

This commit is contained in:
Alex Unger
2021-04-28 13:33:46 +02:00
committed by GitHub
7 changed files with 186 additions and 18 deletions

View File

@@ -454,7 +454,6 @@ def localApiTests(ctx, storage = 'owncloud', suite = 'apiBugDemonstration', acco
'environment' : {
'TEST_SERVER_URL': 'https://ocis-server:9200',
'OCIS_REVA_DATA_ROOT': '%s' % ('/srv/app/tmp/ocis/owncloud/data/' if storage == 'owncloud' else ''),
'DELETE_USER_DATA_CMD': '%s' % ('' if storage == 'owncloud' else 'rm -rf /srv/app/tmp/ocis/storage/users/nodes/root/* /srv/app/tmp/ocis/storage/users/nodes/*-*-*-*'),
'SKELETON_DIR': '/srv/app/tmp/testing/data/apiSkeleton',
'OCIS_SKELETON_STRATEGY': '%s' % ('copy' if storage == 'owncloud' else 'upload'),
'TEST_OCIS':'true',
@@ -501,7 +500,6 @@ def coreApiTests(ctx, part_number = 1, number_of_parts = 1, storage = 'owncloud'
'environment' : {
'TEST_SERVER_URL': 'https://ocis-server:9200',
'OCIS_REVA_DATA_ROOT': '%s' % ('/srv/app/tmp/ocis/owncloud/data/' if storage == 'owncloud' else ''),
'DELETE_USER_DATA_CMD': '%s' % ('' if storage == 'owncloud' else 'rm -rf /srv/app/tmp/ocis/storage/users/nodes/root/* /srv/app/tmp/ocis/storage/users/nodes/*-*-*-*'),
'SKELETON_DIR': '/srv/app/tmp/testing/data/apiSkeleton',
'OCIS_SKELETON_STRATEGY': '%s' % ('copy' if storage == 'owncloud' else 'upload'),
'TEST_OCIS':'true',

View File

@@ -0,0 +1,15 @@
Enhancement: User Deprovisioning for the OCS API
Use the CS3 API and Reva to deprovision users completely.
Two new environment variables introduced:
```
OCS_IDM_ADDRESS
OCS_STORAGE_USERS_DRIVER
```
`OCS_IDM_ADDRESS` is also an alias for `OCIS_URL`; allows the OCS service to mint jwt tokens for the authenticated user that will be read by the reva authentication middleware.
`OCS_STORAGE_USERS_DRIVER` determines how a user is deprovisioned. This kind of behavior is needed since every storage driver deals with deleting differently.
https://github.com/owncloud/ocis/pull/1962

View File

@@ -22,12 +22,14 @@ require (
github.com/owncloud/ocis/proxy v0.0.0-20210412105747-9b95e9b1191b
github.com/owncloud/ocis/settings v0.0.0-20210413063522-955bd60edf33
github.com/owncloud/ocis/store v0.0.0-20210413063522-955bd60edf33
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.10.0
github.com/spf13/viper v1.7.1
github.com/stretchr/testify v1.7.0
github.com/thejerf/suture/v4 v4.0.0
go.opencensus.io v0.23.0
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea
google.golang.org/grpc v1.37.0 // indirect
google.golang.org/protobuf v1.26.0
)

View File

@@ -45,17 +45,26 @@ type TokenManager struct {
JWTSecret string
}
// IdentityManagement keeps track of the OIDC address. This is because Reva requisite of uniqueness for users
// is based in the combination of IDP hostname + UserID. For more information see:
// https://github.com/cs3org/reva/blob/4fd0229f13fae5bc9684556a82dbbd0eced65ef9/pkg/storage/utils/decomposedfs/node/node.go#L856-L865
type IdentityManagement struct {
Address string
}
// Config combines all available configuration parts.
type Config struct {
File string
Log Log
Debug Debug
HTTP HTTP
Tracing Tracing
TokenManager TokenManager
Service Service
AccountBackend string
RevaAddress string
File string
Log Log
Debug Debug
HTTP HTTP
Tracing Tracing
TokenManager TokenManager
Service Service
AccountBackend string
RevaAddress string
StorageUsersDriver string
IdentityManagement IdentityManagement
Context context.Context
Supervised bool

View File

@@ -165,6 +165,20 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
EnvVars: []string{"OCS_REVA_GATEWAY_ADDR"},
Destination: &cfg.RevaAddress,
},
&cli.StringFlag{
Name: "idm-address",
Value: flags.OverrideDefaultString(cfg.IdentityManagement.Address, "https://localhost:9200"),
EnvVars: []string{"OCS_IDM_ADDRESS", "OCIS_URL"},
Usage: "keeps track of the IDM Address. Needed because of Reva requisite of uniqueness for users",
Destination: &cfg.IdentityManagement.Address,
},
&cli.StringFlag{
Name: "users-driver",
Value: flags.OverrideDefaultString(cfg.StorageUsersDriver, "ocis"),
Usage: "storage driver for users mount: eg. local, eos, owncloud, ocis or s3",
EnvVars: []string{"OCS_STORAGE_USERS_DRIVER", "STORAGE_USERS_DRIVER"},
Destination: &cfg.StorageUsersDriver,
},
}
}

View File

@@ -10,18 +10,27 @@ import (
"strings"
"github.com/asim/go-micro/plugins/client/grpc/v3"
merrors "github.com/asim/go-micro/v3/errors"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
revauser "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/jwt"
"github.com/cs3org/reva/pkg/user"
"github.com/go-chi/chi"
"github.com/go-chi/render"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/protobuf/types/known/fieldmaskpb"
merrors "github.com/asim/go-micro/v3/errors"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocs/pkg/service/v0/data"
"github.com/owncloud/ocis/ocs/pkg/service/v0/response"
storepb "github.com/owncloud/ocis/store/pkg/proto/v0"
"github.com/pkg/errors"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/fieldmaskpb"
)
// GetSelf returns the currently logged in user
@@ -358,6 +367,100 @@ func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) {
return
}
if o.config.RevaAddress != "" && o.config.StorageUsersDriver != "owncloud" {
t, err := o.mintTokenForUser(r.Context(), account)
if err != nil {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, errors.Wrap(err, "error minting token").Error())))
return
}
ctx := metadata.AppendToOutgoingContext(r.Context(), token.TokenHeader, t)
gwc, err := pool.GetGatewayServiceClient(o.config.RevaAddress)
if err != nil {
o.logger.Error().Err(err).Msg("error securing a connection to Reva gateway")
}
homeResp, err := gwc.GetHome(ctx, &provider.GetHomeRequest{})
if err != nil {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, errors.Wrap(err, "could not get home").Error())))
return
}
if homeResp.Status.Code != rpcv1beta1.Code_CODE_OK {
o.logger.Error().
Str("stat_status_code", homeResp.Status.Code.String()).
Str("stat_message", homeResp.Status.Message).
Msg("DeleteUser: could not get user home: get failed")
return
}
statResp, err := gwc.Stat(ctx, &provider.StatRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{
Path: homeResp.Path,
},
},
})
if err != nil {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, errors.Wrap(err, "could not stat home").Error())))
return
}
if statResp.Status.Code != rpcv1beta1.Code_CODE_OK {
o.logger.Error().
Str("stat_status_code", statResp.Status.Code.String()).
Str("stat_message", statResp.Status.Message).
Msg("DeleteUser: could not delete user home: stat failed")
return
}
delReq := &provider.DeleteRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Id{
Id: statResp.Info.Id,
},
},
}
delResp, err := gwc.Delete(ctx, delReq)
if err != nil {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, errors.Wrap(err, "could not delete home").Error())))
return
}
if delResp.Status.Code != rpcv1beta1.Code_CODE_OK {
o.logger.Error().
Str("stat_status_code", statResp.Status.Code.String()).
Str("stat_message", statResp.Status.Message).
Msg("DeleteUser: could not delete user home: delete failed")
return
}
req := &gateway.PurgeRecycleRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{
Path: homeResp.Path,
},
},
}
purgeRecycleResponse, err := gwc.PurgeRecycle(ctx, req)
if err != nil {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, errors.Wrap(err, "could not delete trash").Error())))
return
}
if purgeRecycleResponse.Status.Code != rpcv1beta1.Code_CODE_OK {
o.logger.Error().
Str("stat_status_code", statResp.Status.Code.String()).
Str("stat_message", statResp.Status.Message).
Msg("DeleteUser: could not delete user trash: delete failed")
return
}
}
req := accounts.DeleteAccountRequest{
Id: account.Id,
}
@@ -378,6 +481,35 @@ func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) {
mustNotFail(render.Render(w, r, response.DataRender(struct{}{})))
}
// TODO(refs) this to ocis-pkg ... we are minting tokens all over the place ... or use a service? ... like reva?
func (o Ocs) mintTokenForUser(ctx context.Context, account *accounts.Account) (string, error) {
tm, _ := jwt.New(map[string]interface{}{
"secret": o.config.TokenManager.JWTSecret,
"expires": int64(60),
})
u := &revauser.User{
Id: &revauser.UserId{
OpaqueId: account.Id,
Idp: o.config.IdentityManagement.Address,
},
Groups: []string{},
Opaque: &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"uid": {
Decoder: "plain",
Value: []byte(strconv.FormatInt(account.UidNumber, 10)),
},
"gid": {
Decoder: "plain",
Value: []byte(strconv.FormatInt(account.GidNumber, 10)),
},
},
},
}
return tm.MintToken(ctx, u)
}
// EnableUser enables a user
func (o Ocs) EnableUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid")

View File

@@ -1539,8 +1539,6 @@ special character username not valid
- [apiProvisioning-v2/enableUser.feature:20](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiProvisioning-v2/enableUser.feature#L20)
- [apiProvisioning-v2/getUser.feature:34](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiProvisioning-v2/getUser.feature#L34)
- [apiProvisioning-v2/getUser.feature:35](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiProvisioning-v2/getUser.feature#L35)
- [apiTrashbin/trashbinFilesFolders.feature:201](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L201)
- [apiTrashbin/trashbinFilesFolders.feature:202](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L202)
- [apiTrashbin/trashbinFilesFolders.feature:246](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L246)
- [apiTrashbin/trashbinFilesFolders.feature:247](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L247)
- [apiTrashbin/trashbinFilesFolders.feature:248](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L248)