Repository: owncloud/ocis
Pull request #6103 (2023-04-20 20:27:28)

listing drives sould use the user filter
when a user lists all spaces he has access to (unrestricted==false) we should send a user filter, so decomposedfs has a chance to use an index instead of iterating over ALL spaces.

part of todays tracing session, the reva part is in https://github.com/cs3org/reva/pull/3809

~~blocked by https://github.com/cs3org/reva/pull/3826~~
blocked by https://github.com/cs3org/reva/pull/3827

update-docs[bot]: Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would create a [changelog](https://github.com/owncloud/ocis/blob/master/changelog/README.md) item based on your changes.

ownclouders: :boom: Acceptance test [<strong>localApiTests-apiSpaces-ocis</strong>](https://drone.owncloud.com/owncloud/ocis/21706/52/1) failed. Further test are cancelled...
<!-- id: pr-6103 -->

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=6103)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL)

[![75.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/60-16px.png '75.0%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list) [75.0% Coverage](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list)


butonic: @aduffeck duh we are not invalidating the filemetadata cache when deleting a space ...

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=6103)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL)

[![76.9%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/60-16px.png '76.9%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list) [76.9% Coverage](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=6103)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL)

[![76.9%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/60-16px.png '76.9%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list) [76.9% Coverage](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=6103)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL)

[![76.9%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/60-16px.png '76.9%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list) [76.9% Coverage](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=6103)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=6103&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=6103&resolved=false&types=CODE_SMELL)

[![76.9%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/60-16px.png '76.9%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list) [76.9% Coverage](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=6103&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/go.mod b/go.mod
index 11d438cc625..ac51b435f96 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
 	github.com/coreos/go-oidc v2.2.1+incompatible
 	github.com/coreos/go-oidc/v3 v3.4.0
 	github.com/cs3org/go-cs3apis v0.0.0-20221012090518-ef2996678965
-	github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1
+	github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5
 	github.com/disintegration/imaging v1.6.2
 	github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
 	github.com/egirna/icap-client v0.1.1
diff --git a/go.sum b/go.sum
index 00ecd3d2f93..d005bd0df03 100644
--- a/go.sum
+++ b/go.sum
@@ -627,8 +627,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
 github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
 github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
 github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
-github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1 h1:p563+4bqdVSYPtDeo6ikOEbciU/mjbYhrei2zCjzxkw=
-github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1/go.mod h1:VxBmpOvIKlgKLPOsHun+fABopzX+3ZELPAp3N5bQMsM=
+github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5 h1:wloX5LiqRxwh2ID9O+em8O5VU1h2ZN5u6tPceAdLNDI=
+github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5/go.mod h1:VxBmpOvIKlgKLPOsHun+fABopzX+3ZELPAp3N5bQMsM=
 github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
 github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
 github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
diff --git a/services/graph/pkg/service/v0/drives.go b/services/graph/pkg/service/v0/drives.go
index 914167f8e95..e15402a5080 100644
--- a/services/graph/pkg/service/v0/drives.go
+++ b/services/graph/pkg/service/v0/drives.go
@@ -91,6 +91,20 @@ func (g Graph) getDrives(w http.ResponseWriter, r *http.Request, unrestricted bo
 		errorcode.NotSupported.Render(w, r, http.StatusNotImplemented, err.Error())
 		return
 	}
+	if !unrestricted {
+		user, ok := revactx.ContextGetUser(r.Context())
+		if !ok {
+			logger.Debug().Msg("could not create drive: invalid user")
+			errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "invalid user")
+			return
+		}
+		filters = append(filters, &storageprovider.ListStorageSpacesRequest_Filter{
+			Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_USER,
+			Term: &storageprovider.ListStorageSpacesRequest_Filter_User{
+				User: user.GetId(),
+			},
+		})
+	}
 
 	logger.Debug().
 		Interface("filters", filters).
@@ -240,7 +254,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
 	if !canCreateSpace {
 		logger.Debug().Bool("cancreatespace", canCreateSpace).Msg("could not create drive: insufficient permissions")
 		// if the permission is not existing for the user in context we can assume we don't have it. Return 401.
-		errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "insufficient permissions to create a space.")
+		errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "insufficient permissions to create a space.")
 		return
 	}
 
diff --git a/services/storage-system/pkg/config/config.go b/services/storage-system/pkg/config/config.go
index ccc4ac1c967..b83bd7be207 100644
--- a/services/storage-system/pkg/config/config.go
+++ b/services/storage-system/pkg/config/config.go
@@ -85,7 +85,7 @@ type Drivers struct {
 
 // OCISDriver holds ocis Driver config
 type OCISDriver struct {
-	MetadataBackend string `yaml:"metadata_backend" env:"OCIS_DECOMPOSEDFS_METADATA_BACKEND;STORAGE_SYSTEM_OCIS_METADATA_BACKEND" desc:"The backend to use for storing metadata. Supported values are 'xattrs' and 'ini'. The setting 'xattrs' uses extended attributes to store file metadata while 'ini' uses a dedicated file to store file metadata. Defaults to 'xattrs'."`
+	MetadataBackend string `yaml:"metadata_backend" env:"OCIS_DECOMPOSEDFS_METADATA_BACKEND;STORAGE_SYSTEM_OCIS_METADATA_BACKEND" desc:"The backend to use for storing metadata. Supported values are 'xattrs' and 'messagepack'. The setting 'xattrs' uses extended attributes to store file metadata while 'messagepack' uses a dedicated file to store file metadata. Defaults to 'xattrs'."`
 	// Root is the absolute path to the location of the data
 	Root string `yaml:"root" env:"STORAGE_SYSTEM_OCIS_ROOT" desc:"Path for the directory where the STORAGE-SYSTEM service stores it's persistent data. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage."`
 
diff --git a/services/storage-users/pkg/config/config.go b/services/storage-users/pkg/config/config.go
index fd160cef313..f6af0c48ecd 100644
--- a/services/storage-users/pkg/config/config.go
+++ b/services/storage-users/pkg/config/config.go
@@ -99,7 +99,7 @@ type Drivers struct {
 
 // OCISDriver is the storage driver configuration when using 'ocis' storage driver
 type OCISDriver struct {
-	MetadataBackend string `yaml:"metadata_backend" env:"OCIS_DECOMPOSEDFS_METADATA_BACKEND;STORAGE_USERS_OCIS_METADATA_BACKEND" desc:"The backend to use for storing metadata. Supported values are 'xattrs' and 'ini'. The setting 'xattrs' uses extended attributes to store file metadata while 'ini' uses a dedicated file to store file metadata. Defaults to 'xattrs'."`
+	MetadataBackend string `yaml:"metadata_backend" env:"OCIS_DECOMPOSEDFS_METADATA_BACKEND;STORAGE_USERS_OCIS_METADATA_BACKEND" desc:"The backend to use for storing metadata. Supported values are 'xattrs' and 'messagepack'. The setting 'xattrs' uses extended attributes to store file metadata while 'messagepack' uses a dedicated file to store file metadata. Defaults to 'xattrs'."`
 	// Root is the absolute path to the location of the data
 	Root                string `yaml:"root" env:"STORAGE_USERS_OCIS_ROOT" desc:"The directory where the filesystem storage will store blobs and metadata. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage/users."`
 	UserLayout          string `yaml:"user_layout" env:"STORAGE_USERS_OCIS_USER_LAYOUT" desc:"Template string for the user storage layout in the user directory."`
@@ -121,7 +121,7 @@ type OCISDriver struct {
 
 // S3NGDriver is the storage driver configuration when using 's3ng' storage driver
 type S3NGDriver struct {
-	MetadataBackend string `yaml:"metadata_backend" env:"STORAGE_USERS_S3NG_METADATA_BACKEND" desc:"The backend to use for storing metadata. Supported values are 'xattrs' and 'ini'. The setting 'xattrs' uses extended attributes to store file metadata while 'ini' uses a dedicated file to store file metadata. Defaults to 'xattrs'."`
+	MetadataBackend string `yaml:"metadata_backend" env:"STORAGE_USERS_S3NG_METADATA_BACKEND" desc:"The backend to use for storing metadata. Supported values are 'xattrs' and 'messagepack'. The setting 'xattrs' uses extended attributes to store file metadata while 'messagepack' uses a dedicated file to store file metadata. Defaults to 'xattrs'."`
 	// Root is the absolute path to the location of the data
 	Root                string `yaml:"root" env:"STORAGE_USERS_S3NG_ROOT" desc:"The directory where the filesystem storage will store metadata for blobs. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage/users."`
 	UserLayout          string `yaml:"user_layout" env:"STORAGE_USERS_S3NG_USER_LAYOUT" desc:"Template string for the user storage layout in the user directory."`
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/decomposedfs.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/decomposedfs.go
index fc051372ea0..4a8d0d0a5fb 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/decomposedfs.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/decomposedfs.go
@@ -57,6 +57,7 @@ import (
 	"github.com/cs3org/reva/v2/pkg/storage/utils/templates"
 	"github.com/cs3org/reva/v2/pkg/storagespace"
 	"github.com/cs3org/reva/v2/pkg/utils"
+	"github.com/jellydator/ttlcache/v2"
 	"github.com/pkg/errors"
 	"golang.org/x/sync/errgroup"
 )
@@ -95,6 +96,8 @@ type Decomposedfs struct {
 	chunkHandler *chunking.ChunkHandler
 	stream       events.Stream
 	cache        cache.StatCache
+
+	UserCache *ttlcache.Cache
 }
 
 // NewDefault returns an instance with default components
@@ -160,6 +163,7 @@ func New(o *options.Options, lu *lookup.Lookup, p Permissions, tp Tree, es event
 		chunkHandler: chunking.NewChunkHandler(filepath.Join(o.Root, "uploads")),
 		stream:       es,
 		cache:        cache.GetStatCache(o.StatCache.Store, o.StatCache.Nodes, o.StatCache.Database, "stat", time.Duration(o.StatCache.TTL)*time.Second, o.StatCache.Size),
+		UserCache:    ttlcache.NewCache(),
 	}
 
 	if o.AsyncFileUploads {
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/grants.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/grants.go
index 5a86fa77265..0e162e6aabe 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/grants.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/grants.go
@@ -201,8 +201,6 @@ func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference
 		return err
 	}
 
-	spaceGrant := ctx.Value(utils.SpaceGrant)
-
 	var attr string
 	if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
 		attr = prefixes.GrantGroupAcePrefix + g.Grantee.GetGroupId().OpaqueId
@@ -214,18 +212,34 @@ func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference
 		return err
 	}
 
-	// TODO we need an index for groups
-	if spaceGrant != nil && g.Grantee.Type != provider.GranteeType_GRANTEE_TYPE_GROUP {
-		// remove from user index
-		userIDPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", g.Grantee.GetUserId().OpaqueId, grantNode.SpaceID)
-		if err := os.Remove(userIDPath); err != nil {
-			return err
+	if isShareGrant(ctx) {
+		// do not invalidate by user or group indexes
+		// FIXME we should invalidate the by-type index, but that requires reference counting
+	} else {
+		// invalidate space grant
+		switch {
+		case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER:
+			// remove from user index
+			userIDPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", g.Grantee.GetUserId().GetOpaqueId(), grantNode.SpaceID)
+			if err := os.Remove(userIDPath); err != nil {
+				return err
+			}
+		case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP:
+			// remove from group index
+			userIDPath := filepath.Join(fs.o.Root, "indexes", "by-group-id", g.Grantee.GetGroupId().GetOpaqueId(), grantNode.SpaceID)
+			if err := os.Remove(userIDPath); err != nil {
+				return err
+			}
 		}
 	}
 
 	return fs.tp.Propagate(ctx, grantNode, 0)
 }
 
+func isShareGrant(ctx context.Context) bool {
+	return ctx.Value(utils.SpaceGrant) == nil
+}
+
 // UpdateGrant updates a grant on a resource
 // TODO remove AddGrant or UpdateGrant grant from CS3 api, redundant? tracked in https://github.com/cs3org/cs3apis/issues/92
 func (fs *Decomposedfs) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
@@ -319,7 +333,7 @@ func (fs *Decomposedfs) storeGrant(ctx context.Context, n *node.Node, g *provide
 	}
 
 	// update the indexes only after successfully setting the grant
-	err := fs.updateIndexes(ctx, g.GetGrantee().GetUserId().GetOpaqueId(), spaceType, n.ID)
+	err := fs.updateIndexes(ctx, g.GetGrantee(), spaceType, n.ID)
 	if err != nil {
 		return err
 	}
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/node.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/node.go
index c802ebfa1ec..bd3726e7bca 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/node.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/node.go
@@ -1046,19 +1046,46 @@ func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap prov
 
 // IsDenied checks if the node was denied to that user
 func (n *Node) IsDenied(ctx context.Context) bool {
-	u := ctxpkg.ContextMustGetUser(ctx)
-	userace := prefixes.GrantUserAcePrefix + u.Id.OpaqueId
-	g, err := n.ReadGrant(ctx, userace)
-	switch {
-	case err == nil:
-		// If all permissions are set to false we have a deny grant
-		return grants.PermissionsEqual(g.Permissions, &provider.ResourcePermissions{})
-	case metadata.IsAttrUnset(err):
-		return false
-	default:
+	gs, err := n.ListGrants(ctx)
+	if err != nil {
 		// be paranoid, resource is denied
 		return true
 	}
+
+	u := ctxpkg.ContextMustGetUser(ctx)
+	isExecutant := func(g *provider.Grantee) bool {
+		switch g.GetType() {
+		case provider.GranteeType_GRANTEE_TYPE_USER:
+			return g.GetUserId().GetOpaqueId() == u.GetId().GetOpaqueId()
+		case provider.GranteeType_GRANTEE_TYPE_GROUP:
+			// check gid
+			gid := g.GetGroupId().GetOpaqueId()
+			for _, group := range u.Groups {
+				if gid == group {
+					return true
+				}
+
+			}
+			return false
+		default:
+			return false
+		}
+
+	}
+
+	for _, g := range gs {
+		if !isExecutant(g.Grantee) {
+			continue
+		}
+
+		if grants.PermissionsEqual(g.Permissions, &provider.ResourcePermissions{}) {
+			// resource is denied
+			return true
+		}
+	}
+
+	// no deny grants
+	return false
 }
 
 // ListGrantees lists the grantees of the current node
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options/options.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options/options.go
index 971f682f533..ae752b4fc48 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options/options.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options/options.go
@@ -35,6 +35,9 @@ type Option func(o *Options)
 // Options defines the available options for this package.
 type Options struct {
 
+	// the gateway address
+	GatewayAddr string `mapstructure:"gateway_addr"`
+
 	// the metadata backend to use, currently supports `xattr` or `ini`
 	MetadataBackend string `mapstructure:"metadata_backend"`
 
@@ -99,6 +102,8 @@ func New(m map[string]interface{}) (*Options, error) {
 		return nil, err
 	}
 
+	o.GatewayAddr = sharedconf.GetGatewaySVC(o.GatewayAddr)
+
 	if o.MetadataBackend == "" {
 		o.MetadataBackend = "xattrs"
 	}
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spacepermissions.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spacepermissions.go
index 43ab99cefe3..ce764f8e0e7 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spacepermissions.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spacepermissions.go
@@ -3,11 +3,13 @@ package decomposedfs
 import (
 	"context"
 
+	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
 	cs3permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
 	v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
 	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
 	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
 	"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
+	"github.com/cs3org/reva/v2/pkg/utils"
 	"google.golang.org/grpc"
 )
 
@@ -70,12 +72,12 @@ func (p Permissions) ListAllSpaces(ctx context.Context) bool {
 }
 
 // ListSpacesOfUser returns true when the user is allowed to list the spaces of the given user
-func (p Permissions) ListSpacesOfUser(ctx context.Context, userid string) bool {
-	switch userid {
-	case userIDAny:
+func (p Permissions) ListSpacesOfUser(ctx context.Context, userid *userv1beta1.UserId) bool {
+	switch {
+	case userid == nil:
 		// there is no filter
 		return true // TODO: is `true` actually correct here? Shouldn't we check for ListAllSpaces too?
-	case ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId():
+	case utils.UserIDEqual(ctxpkg.ContextMustGetUser(ctx).GetId(), userid):
 		return true
 	default:
 		return p.ListAllSpaces(ctx)
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go
index 4fced4f99f0..f39fc4bc98f 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go
@@ -37,6 +37,7 @@ import (
 	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
 	"github.com/cs3org/reva/v2/pkg/errtypes"
 	"github.com/cs3org/reva/v2/pkg/rgrpc/status"
+	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
 	"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/lookup"
 	"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes"
 	"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
@@ -54,13 +55,13 @@ const (
 	spaceTypeShare     = "share"
 	spaceTypeAny       = "*"
 	spaceIDAny         = "*"
-	userIDAny          = "*"
 
 	quotaUnrestricted = 0
 )
 
 // CreateStorageSpace creates a storage space
 func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) {
+	ctx = context.WithValue(ctx, utils.SpaceGrant, struct{}{})
 
 	// "everything is a resource" this is the unique ID for the Space resource.
 	spaceID := uuid.New().String()
@@ -147,7 +148,10 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr
 	}
 
 	// Write index
-	err = fs.updateIndexes(ctx, req.GetOwner().GetId().GetOpaqueId(), req.Type, root.ID)
+	err = fs.updateIndexes(ctx, &provider.Grantee{
+		Type: provider.GranteeType_GRANTEE_TYPE_USER,
+		Id:   &provider.Grantee_UserId{UserId: req.GetOwner().GetId()},
+	}, req.Type, root.ID)
 	if err != nil {
 		return nil, err
 	}
@@ -218,7 +222,7 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
 	var (
 		spaceID         = spaceIDAny
 		nodeID          = spaceIDAny
-		requestedUserID = userIDAny
+		requestedUserID *userv1beta1.UserId
 	)
 
 	spaceTypes := map[string]struct{}{}
@@ -241,10 +245,10 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
 			}
 		case provider.ListStorageSpacesRequest_Filter_TYPE_USER:
 			// TODO: refactor this to GetUserId() in cs3
-			requestedUserID = filter[i].GetUser().GetOpaqueId()
+			requestedUserID = filter[i].GetUser()
 		case provider.ListStorageSpacesRequest_Filter_TYPE_OWNER:
 			// TODO: improve further by not evaluating shares
-			requestedUserID = filter[i].GetOwner().GetOpaqueId()
+			requestedUserID = filter[i].GetOwner()
 		}
 	}
 	if len(spaceTypes) == 0 {
@@ -292,8 +296,8 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
 
 	matches := map[string]struct{}{}
 
-	if requestedUserID != userIDAny {
-		path := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID, nodeID)
+	if requestedUserID != nil {
+		path := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID.GetOpaqueId(), nodeID)
 		m, err := filepath.Glob(path)
 		if err != nil {
 			return nil, err
@@ -305,9 +309,35 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
 			}
 			matches[link] = struct{}{}
 		}
+
+		// get Groups for userid
+		user := ctxpkg.ContextMustGetUser(ctx)
+		// TODO the user from context may not have groups populated
+		if !utils.UserIDEqual(user.GetId(), requestedUserID) {
+			user, err = fs.UserIDToUserAndGroups(ctx, requestedUserID)
+			if err != nil {
+				return nil, err // TODO log and continue?
+			}
+		}
+
+		for _, group := range user.Groups {
+			path := filepath.Join(fs.o.Root, "indexes", "by-group-id", group, nodeID)
+			m, err := filepath.Glob(path)
+			if err != nil {
+				return nil, err
+			}
+			for _, match := range m {
+				link, err := os.Readlink(match)
+				if err != nil {
+					continue
+				}
+				matches[link] = struct{}{}
+			}
+		}
+
 	}
 
-	if requestedUserID == userIDAny {
+	if requestedUserID == nil {
 		for spaceType := range spaceTypes {
 			path := filepath.Join(fs.o.Root, "indexes", "by-type", spaceType, nodeID)
 			m, err := filepath.Glob(path)
@@ -412,6 +442,31 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
 
 }
 
+// UserIDToUserAndGroups converts a user ID to a user with groups
+func (fs *Decomposedfs) UserIDToUserAndGroups(ctx context.Context, userid *userv1beta1.UserId) (*userv1beta1.User, error) {
+	user, err := fs.UserCache.Get(userid.GetOpaqueId())
+	if err == nil {
+		return user.(*userv1beta1.User), nil
+	}
+
+	gwConn, err := pool.GetGatewayServiceClient(fs.o.GatewayAddr)
+	if err != nil {
+		return nil, err
+	}
+	getUserResponse, err := gwConn.GetUser(ctx, &userv1beta1.GetUserRequest{
+		UserId:                 userid,
+		SkipFetchingUserGroups: false,
+	})
+	if err != nil {
+		return nil, err
+	}
+	if getUserResponse.Status.Code != v1beta11.Code_CODE_OK {
+		return nil, status.NewErrorFromCode(getUserResponse.Status.Code, "gateway")
+	}
+	_ = fs.UserCache.Set(userid.GetOpaqueId(), getUserResponse.GetUser())
+	return getUserResponse.GetUser(), nil
+}
+
 // MustCheckNodePermissions checks if permission checks are needed to be performed when user requests spaces
 func (fs *Decomposedfs) MustCheckNodePermissions(ctx context.Context, unrestricted bool) bool {
 	// canListAllSpaces indicates if the user has the permission from the global user role
@@ -649,12 +704,26 @@ func (fs *Decomposedfs) DeleteStorageSpace(ctx context.Context, req *provider.De
 	return n.SetDTime(&dtime)
 }
 
-func (fs *Decomposedfs) updateIndexes(ctx context.Context, userID, spaceType, spaceID string) error {
+func (fs *Decomposedfs) updateIndexes(ctx context.Context, grantee *provider.Grantee, spaceType, spaceID string) error {
 	err := fs.linkStorageSpaceType(ctx, spaceType, spaceID)
 	if err != nil {
 		return err
 	}
-	return fs.linkSpaceByUser(ctx, userID, spaceID)
+	if isShareGrant(ctx) {
+		// FIXME we should count the references for the by-type index currently removing the second share from the same
+		// space cannot determine if the by-type should be deletet, which is why we never delete them ...
+		return nil
+	}
+
+	// create space grant index
+	switch {
+	case grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER:
+		return fs.linkSpaceByUser(ctx, grantee.GetUserId().GetOpaqueId(), spaceID)
+	case grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP:
+		return fs.linkSpaceByGroup(ctx, grantee.GetGroupId().GetOpaqueId(), spaceID)
+	default:
+		return errtypes.BadRequest("invalid grantee type: " + grantee.GetType().String())
+	}
 }
 
 func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID string) error {
@@ -681,6 +750,30 @@ func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID str
 	return nil
 }
 
+func (fs *Decomposedfs) linkSpaceByGroup(ctx context.Context, groupID, spaceID string) error {
+	if groupID == "" {
+		return nil
+	}
+	// create group index dir
+	// TODO: pathify groupid
+	if err := os.MkdirAll(filepath.Join(fs.o.Root, "indexes", "by-group-id", groupID), 0700); err != nil {
+		return err
+	}
+
+	err := os.Symlink("../../../spaces/"+lookup.Pathify(spaceID, 1, 2)+"/nodes/"+lookup.Pathify(spaceID, 4, 2), filepath.Join(fs.o.Root, "indexes/by-group-id", groupID, spaceID))
+	if err != nil {
+		if isAlreadyExists(err) {
+			appctx.GetLogger(ctx).Debug().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("symlink already exists")
+			// FIXME: is it ok to wipe this err if the symlink already exists?
+			err = nil //nolint
+		} else {
+			// TODO how should we handle error cases here?
+			appctx.GetLogger(ctx).Error().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("could not create symlink")
+		}
+	}
+	return nil
+}
+
 // TODO: implement linkSpaceByGroup
 
 func (fs *Decomposedfs) linkStorageSpaceType(ctx context.Context, spaceType string, spaceID string) error {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index bd92942e0f6..65978eab29f 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -349,7 +349,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
 github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
 github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
 github.com/cs3org/go-cs3apis/cs3/types/v1beta1
-# github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1
+# github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5
 ## explicit; go 1.19
 github.com/cs3org/reva/v2/cmd/revad/internal/grace
 github.com/cs3org/reva/v2/cmd/revad/runtime


Test patch:
diff --git a/services/graph/pkg/service/v0/graph_test.go b/services/graph/pkg/service/v0/graph_test.go
index 7f63e681533..aace93a770c 100644
--- a/services/graph/pkg/service/v0/graph_test.go
+++ b/services/graph/pkg/service/v0/graph_test.go
@@ -90,6 +90,7 @@ var _ = Describe("Graph", func() {
 				}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 				Expect(rr.Code).To(Equal(http.StatusOK))
@@ -102,6 +103,7 @@ var _ = Describe("Graph", func() {
 				}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/drives", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetAllDrives(rr, r)
 				Expect(rr.Code).To(Equal(http.StatusOK))
@@ -131,6 +133,7 @@ var _ = Describe("Graph", func() {
 				}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 
@@ -201,6 +204,7 @@ var _ = Describe("Graph", func() {
 				}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives?$orderby=name%20asc", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 
@@ -281,6 +285,7 @@ var _ = Describe("Graph", func() {
 				}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 
@@ -320,6 +325,7 @@ var _ = Describe("Graph", func() {
 				}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives?$orderby=owner%20asc", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 				Expect(rr.Code).To(Equal(http.StatusBadRequest))
@@ -361,6 +367,7 @@ var _ = Describe("Graph", func() {
 				gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(nil, errors.New("transport error"))
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 				Expect(rr.Code).To(Equal(http.StatusInternalServerError))
@@ -378,6 +385,7 @@ var _ = Describe("Graph", func() {
 					StorageSpaces: []*provider.StorageSpace{}}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 				Expect(rr.Code).To(Equal(http.StatusInternalServerError))
@@ -395,6 +403,7 @@ var _ = Describe("Graph", func() {
 					StorageSpaces: []*provider.StorageSpace{}}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 				Expect(rr.Code).To(Equal(http.StatusOK))
@@ -430,6 +439,7 @@ var _ = Describe("Graph", func() {
 				}, nil)
 
 				r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
+				r = r.WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.GetDrives(rr, r)
 
@@ -469,7 +479,7 @@ var _ = Describe("Graph", func() {
 				r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/drives", bytes.NewBuffer(jsonBody)).WithContext(ctx)
 				rr := httptest.NewRecorder()
 				svc.CreateDrive(rr, r)
-				Expect(rr.Code).To(Equal(http.StatusUnauthorized))
+				Expect(rr.Code).To(Equal(http.StatusForbidden))
 
 				body, _ := io.ReadAll(rr.Body)
 				var libreError libregraph.OdataError
diff --git a/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md b/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md
index bc64f3806e7..55798ab5cd5 100644
--- a/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md
+++ b/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md
@@ -146,8 +146,6 @@ The expected failures in this file are from features in the owncloud/ocis repo.
 - [apiGraph/removeUserFromGroup.feature:192](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L192)
 - [apiGraph/removeUserFromGroup.feature:193](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L193)
 - [apiGraph/removeUserFromGroup.feature:194](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L194)
-- [apiSpaces/createSpace.feature:18](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/createSpace.feature#L18)
-- [apiSpaces/createSpace.feature:19](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/createSpace.feature#L19)
 
 #### [API requests for a non-existent resources should return 404](https://github.com/owncloud/ocis/issues/5939)
 - [apiGraph/addUserToGroup.feature:202](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/addUserToGroup.feature#L202)