Repository: owncloud/ocis
Pull request #9118 (2024-05-09 08:46:39)

[tests-only][full-ci]changing given from ocs to graph in favoritesSharingToShares feature
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
- Part of https://github.com/owncloud/ocis/issues/8717

sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=9118) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=9118&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=9118&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=9118&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Duplication  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=9118)



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5eaf50db996..38e936e73d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -77,6 +77,7 @@ The following sections list the changes for unreleased.
 * Change - Change the default store for presigned keys to nats-js-kv: [#8419](https://github.com/owncloud/ocis/pull/8419)
 * Change - Disable resharing by default for deprecation: [#8653](https://github.com/owncloud/ocis/pull/8653)
 * Change - Define maximum input image dimensions and size when generating previews: [#9035](https://github.com/owncloud/ocis/pull/9035)
+* Change - The `filesystem` backend for the settings service has been removed: [#9138](https://github.com/owncloud/ocis/pull/9138)
 * Enhancement - Introduce staticroutes package & remove well-known OIDC middleware: [#6095](https://github.com/owncloud/ocis/issues/6095)
 * Enhancement - Graphs endpoint for mounting and unmounting shares: [#7885](https://github.com/owncloud/ocis/pull/7885)
 * Enhancement - Add epub reader to web default apps: [#8410](https://github.com/owncloud/ocis/pull/8410)
@@ -345,6 +346,13 @@ The following sections list the changes for unreleased.
    https://github.com/owncloud/ocis/pull/9035
    https://github.com/owncloud/ocis/pull/9069
 
+* Change - The `filesystem` backend for the settings service has been removed: [#9138](https://github.com/owncloud/ocis/pull/9138)
+
+   The only remaining backend for the settings service is `metadata`, which has
+   been the default backend since ocis 2.0
+
+   https://github.com/owncloud/ocis/pull/9138
+
 * Enhancement - Introduce staticroutes package & remove well-known OIDC middleware: [#6095](https://github.com/owncloud/ocis/issues/6095)
 
    We have introduced a new static routes package to the proxy. This package is
diff --git a/changelog/unreleased/remove-deprecated-settings-backend.md b/changelog/unreleased/remove-deprecated-settings-backend.md
new file mode 100644
index 00000000000..81d333176ea
--- /dev/null
+++ b/changelog/unreleased/remove-deprecated-settings-backend.md
@@ -0,0 +1,6 @@
+Change: The `filesystem` backend for the settings service has been removed
+
+The only remaining backend for the settings service is `metadata`, which has been the
+default backend since ocis 2.0
+
+https://github.com/owncloud/ocis/pull/9138
diff --git a/go.mod b/go.mod
index f093da56365..6975e7efdc5 100644
--- a/go.mod
+++ b/go.mod
@@ -75,7 +75,7 @@ require (
 	github.com/owncloud/libre-graph-api-go v1.0.5-0.20240425090020-dba6d1507c38
 	github.com/pkg/errors v0.9.1
 	github.com/pkg/xattr v0.4.9
-	github.com/prometheus/client_golang v1.19.0
+	github.com/prometheus/client_golang v1.19.1
 	github.com/r3labs/sse/v2 v2.10.0
 	github.com/riandyrn/otelchi v0.8.0
 	github.com/rogpeppe/go-internal v1.12.0
@@ -93,7 +93,7 @@ require (
 	github.com/urfave/cli/v2 v2.27.2
 	github.com/xhit/go-simple-mail/v2 v2.16.0
 	go-micro.dev/v4 v4.10.2
-	go.etcd.io/bbolt v1.3.9
+	go.etcd.io/bbolt v1.3.10
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0
 	go.opentelemetry.io/contrib/zpages v0.51.0
 	go.opentelemetry.io/otel v1.26.0
diff --git a/go.sum b/go.sum
index 3da633e41b1..8e54fe5e81f 100644
--- a/go.sum
+++ b/go.sum
@@ -1859,8 +1859,8 @@ github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrb
 github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
 github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
 github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
-github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
-github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
 github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -2087,8 +2087,8 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD
 go-micro.dev/v4 v4.10.2 h1:GWQf1+FcAiMf1yca3P09RNjB31Xtk0C5HiKHSpq/2qA=
 go-micro.dev/v4 v4.10.2/go.mod h1:RV2AolXjTAil9Xm82QCMo1gknuZwD61oMUH14wJpECk=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
-go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
+go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
+go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
 go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c=
 go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
 go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A=
diff --git a/services/graph/pkg/identity/ldap.go b/services/graph/pkg/identity/ldap.go
index efa2fd793f5..dea9f3a6d7e 100644
--- a/services/graph/pkg/identity/ldap.go
+++ b/services/graph/pkg/identity/ldap.go
@@ -21,8 +21,9 @@ import (
 )
 
 const (
-	_givenNameAttribute = "givenname"
-	_surNameAttribute   = "sn"
+	_givenNameAttribute  = "givenname"
+	_surNameAttribute    = "sn"
+	_identitiesAttribute = "oCExternalIdentity"
 )
 
 // DisableUserMechanismType is used instead of directly using the string values from the configuration.
@@ -81,6 +82,7 @@ type userAttributeMap struct {
 	surname        string
 	accountEnabled string
 	userType       string
+	identities     string
 }
 
 type ldapAttributeValues map[string][]string
@@ -114,6 +116,7 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD
 		givenName:      _givenNameAttribute,
 		surname:        _surNameAttribute,
 		userType:       config.UserTypeAttribute,
+		identities:     _identitiesAttribute,
 	}
 
 	if config.GroupNameAttribute == "" || config.GroupIDAttribute == "" {
@@ -338,6 +341,19 @@ func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph.
 		}
 	}
 
+	if identities, ok := user.GetIdentitiesOk(); ok {
+		attrValues := make([]string, 0, len(identities))
+		for _, identity := range identities {
+			identityStr, err := i.identityToLDAPAttrValue(identity)
+			if err != nil {
+				return nil, err
+			}
+			attrValues = append(attrValues, identityStr)
+		}
+		mr.Replace(i.userAttributeMap.identities, attrValues)
+		updateNeeded = true
+	}
+
 	// Behavior of enabling/disabling of users depends on the "disableUserMechanism" config option:
 	//
 	// "attribute": For the upstream user management service which modifies accountEnabled on the user entry
@@ -395,6 +411,7 @@ func (i *LDAP) getUserByDN(dn string) (*ldap.Entry, error) {
 		i.userAttributeMap.givenName,
 		i.userAttributeMap.accountEnabled,
 		i.userAttributeMap.userType,
+		i.userAttributeMap.identities,
 	}
 
 	filter := fmt.Sprintf("(objectClass=%s)", i.userObjectClass)
@@ -519,9 +536,9 @@ func (i *LDAP) getLDAPUserByFilter(filter string) (*ldap.Entry, error) {
 		i.userAttributeMap.userName,
 		i.userAttributeMap.surname,
 		i.userAttributeMap.givenName,
-
 		i.userAttributeMap.accountEnabled,
 		i.userAttributeMap.userType,
+		i.userAttributeMap.identities,
 	}
 	return i.searchLDAPEntryByFilter(i.userBaseDN, attrs, filter)
 }
@@ -601,6 +618,7 @@ func (i *LDAP) GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]*lib
 			i.userAttributeMap.givenName,
 			i.userAttributeMap.accountEnabled,
 			i.userAttributeMap.userType,
+			i.userAttributeMap.identities,
 		},
 		nil,
 	)
@@ -785,7 +803,7 @@ func (i *LDAP) createUserModelFromLDAP(e *ldap.Entry) *libregraph.User {
 	surname := e.GetEqualFoldAttributeValue(i.userAttributeMap.surname)
 
 	if id != "" && opsan != "" {
-		return &libregraph.User{
+		user := &libregraph.User{
 			DisplayName:              pointerOrNil(e.GetEqualFoldAttributeValue(i.userAttributeMap.displayName)),
 			Mail:                     pointerOrNil(e.GetEqualFoldAttributeValue(i.userAttributeMap.mail)),
 			OnPremisesSamAccountName: &opsan,
@@ -795,6 +813,18 @@ func (i *LDAP) createUserModelFromLDAP(e *ldap.Entry) *libregraph.User {
 			UserType:                 pointerOrNil(e.GetEqualFoldAttributeValue(i.userAttributeMap.userType)),
 			AccountEnabled:           booleanOrNil(e.GetEqualFoldAttributeValue(i.userAttributeMap.accountEnabled)),
 		}
+		var identities []libregraph.ObjectIdentity
+		for _, identityStr := range e.GetEqualFoldAttributeValues(i.userAttributeMap.identities) {
+			parts := strings.SplitN(identityStr, "$", 3)
+			identity := libregraph.NewObjectIdentity()
+			identity.SetIssuer(strings.TrimSpace(parts[1]))
+			identity.SetIssuerAssignedId(strings.TrimSpace(parts[2]))
+			identities = append(identities, *identity)
+		}
+		if len(identities) > 0 {
+			user.SetIdentities(identities)
+		}
+		return user
 	}
 	i.logger.Warn().Str("dn", e.DN).Msg("Invalid User. Missing username or id attribute")
 	return nil
@@ -810,6 +840,19 @@ func (i *LDAP) userToLDAPAttrValues(user libregraph.User) (map[string][]string,
 		i.userAttributeMap.userType:    {user.GetUserType()},
 	}
 
+	if identities, ok := user.GetIdentitiesOk(); ok {
+		for _, identity := range identities {
+			identityStr, err := i.identityToLDAPAttrValue(identity)
+			if err != nil {
+				return nil, err
+			}
+			attrs[i.userAttributeMap.identities] = append(
+				attrs[i.userAttributeMap.identities],
+				identityStr,
+			)
+		}
+	}
+
 	if !i.useServerUUID {
 		attrs["owncloudUUID"] = []string{uuid.New().String()}
 	}
@@ -844,6 +887,15 @@ func (i *LDAP) userToLDAPAttrValues(user libregraph.User) (map[string][]string,
 	return attrs, nil
 }
 
+func (i *LDAP) identityToLDAPAttrValue(identity libregraph.ObjectIdentity) (string, error) {
+	// TODO add support for the "signInType" of objectIdentity
+	if identity.GetIssuer() == "" || identity.GetIssuerAssignedId() == "" {
+		return "", fmt.Errorf("missing Attribute for objectIdentity")
+	}
+	identityStr := fmt.Sprintf(" $ %s $ %s", identity.GetIssuer(), identity.GetIssuerAssignedId())
+	return identityStr, nil
+}
+
 func (i *LDAP) getUserAttrTypes() []string {
 	return []string{
 		i.userAttributeMap.displayName,
@@ -857,6 +909,7 @@ func (i *LDAP) getUserAttrTypes() []string {
 		"userPassword",
 		i.userAttributeMap.accountEnabled,
 		i.userAttributeMap.userType,
+		i.userAttributeMap.identities,
 	}
 }
 
diff --git a/services/graph/pkg/identity/ldap_education_user.go b/services/graph/pkg/identity/ldap_education_user.go
index 1ea76ca4e7a..02814a1c089 100644
--- a/services/graph/pkg/identity/ldap_education_user.go
+++ b/services/graph/pkg/identity/ldap_education_user.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"errors"
 	"fmt"
-	"strings"
 
 	"github.com/go-ldap/ldap/v3"
 	libregraph "github.com/owncloud/libre-graph-api-go"
@@ -12,13 +11,11 @@ import (
 )
 
 type educationUserAttributeMap struct {
-	identities  string
 	primaryRole string
 }
 
 func newEducationUserAttributeMap() educationUserAttributeMap {
 	return educationUserAttributeMap{
-		identities:  "oCExternalIdentity",
 		primaryRole: "userClass",
 	}
 }
@@ -164,7 +161,7 @@ func (i *LDAP) UpdateEducationUser(ctx context.Context, nameOrID string, user li
 			}
 			attrValues = append(attrValues, identityStr)
 		}
-		mr.Replace(i.educationConfig.userAttributeMap.identities, attrValues)
+		mr.Replace(i.userAttributeMap.identities, attrValues)
 		updateNeeded = true
 	}
 
@@ -261,6 +258,7 @@ func (i *LDAP) educationUserToUser(eduUser libregraph.EducationUser) *libregraph
 	user.DisplayName = eduUser.DisplayName
 	user.Mail = eduUser.Mail
 	user.UserType = eduUser.UserType
+	user.Identities = eduUser.Identities
 
 	return user
 }
@@ -281,17 +279,6 @@ func (i *LDAP) userToEducationUser(user libregraph.User, e *ldap.Entry) *libregr
 		if primaryRole := e.GetEqualFoldAttributeValue(i.educationConfig.userAttributeMap.primaryRole); primaryRole != "" {
 			eduUser.SetPrimaryRole(primaryRole)
 		}
-		var identities []libregraph.ObjectIdentity
-		for _, identityStr := range e.GetEqualFoldAttributeValues(i.educationConfig.userAttributeMap.identities) {
-			parts := strings.SplitN(identityStr, "$", 3)
-			identity := libregraph.NewObjectIdentity()
-			identity.SetIssuer(strings.TrimSpace(parts[1]))
-			identity.SetIssuerAssignedId(strings.TrimSpace(parts[2]))
-			identities = append(identities, *identity)
-		}
-		if len(identities) > 0 {
-			eduUser.SetIdentities(identities)
-		}
 	}
 
 	return eduUser
@@ -301,29 +288,9 @@ func (i *LDAP) educationUserToLDAPAttrValues(user libregraph.EducationUser, attr
 	if role, ok := user.GetPrimaryRoleOk(); ok {
 		attrs[i.educationConfig.userAttributeMap.primaryRole] = []string{*role}
 	}
-	if identities, ok := user.GetIdentitiesOk(); ok {
-		for _, identity := range identities {
-			identityStr, err := i.identityToLDAPAttrValue(identity)
-			if err != nil {
-				return nil, err
-			}
-			attrs[i.educationConfig.userAttributeMap.identities] = append(
-				attrs[i.educationConfig.userAttributeMap.identities],
-				identityStr,
-			)
-		}
-	}
 	attrs["objectClass"] = append(attrs["objectClass"], i.educationConfig.userObjectClass)
 	return attrs, nil
 }
-func (i *LDAP) identityToLDAPAttrValue(identity libregraph.ObjectIdentity) (string, error) {
-	// TODO add support for the "signInType" of objectIdentity
-	if identity.GetIssuer() == "" || identity.GetIssuerAssignedId() == "" {
-		return "", fmt.Errorf("missing Attribute for objectIdentity")
-	}
-	identityStr := fmt.Sprintf(" $ %s $ %s", identity.GetIssuer(), identity.GetIssuerAssignedId())
-	return identityStr, nil
-}
 
 func (i *LDAP) educationUserToAddRequest(user libregraph.EducationUser) (*ldap.AddRequest, error) {
 	plainUser := i.educationUserToUser(user)
@@ -359,7 +326,7 @@ func (i *LDAP) getEducationUserAttrTypes() []string {
 		i.userAttributeMap.givenName,
 		i.userAttributeMap.accountEnabled,
 		i.userAttributeMap.userType,
-		i.educationConfig.userAttributeMap.identities,
+		i.userAttributeMap.identities,
 		i.educationConfig.userAttributeMap.primaryRole,
 		i.educationConfig.memberOfSchoolAttribute,
 	}
diff --git a/services/proxy/pkg/user/backend/cs3.go b/services/proxy/pkg/user/backend/cs3.go
index 5750cd2ee70..2646c7d3550 100644
--- a/services/proxy/pkg/user/backend/cs3.go
+++ b/services/proxy/pkg/user/backend/cs3.go
@@ -16,6 +16,7 @@ import (
 	"go-micro.dev/v4/selector"
 
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
 	"github.com/owncloud/ocis/v2/ocis-pkg/registry"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
@@ -176,7 +177,7 @@ func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string
 		return nil, err
 	}
 
-	newUser, err := c.libregraphUserFromClaims(newctx, claims)
+	newUser, err := c.libregraphUserFromClaims(claims)
 	if err != nil {
 		c.logger.Error().Err(err).Interface("claims", claims).Msg("Error creating user from claims")
 		return nil, fmt.Errorf("Error creating user from claims: %w", err)
@@ -267,7 +268,7 @@ func (c cs3backend) isAlreadyExists(resp *http.Response) (bool, error) {
 	return false, nil
 }
 
-func (c cs3backend) libregraphUserFromClaims(ctx context.Context, claims map[string]interface{}) (libregraph.User, error) {
+func (c cs3backend) libregraphUserFromClaims(claims map[string]interface{}) (libregraph.User, error) {
 	user := libregraph.User{}
 	if dn, ok := claims[c.autoProvisionClaims.DisplayName].(string); ok {
 		user.SetDisplayName(dn)
@@ -283,6 +284,17 @@ func (c cs3backend) libregraphUserFromClaims(ctx context.Context, claims map[str
 	if mail, ok := claims[c.autoProvisionClaims.Email].(string); ok {
 		user.SetMail(mail)
 	}
+
+	sub, subExists := claims[oidc.Sub].(string)
+	iss, issExists := claims[oidc.Iss].(string)
+
+	if subExists && issExists {
+		var objectIdentity libregraph.ObjectIdentity
+		objectIdentity.SetIssuer(iss)
+		objectIdentity.SetIssuerAssignedId(sub)
+		user.Identities = append(user.Identities, objectIdentity)
+	}
+
 	return user, nil
 }
 
diff --git a/services/settings/README.md b/services/settings/README.md
index 69432c8de83..65672316103 100644
--- a/services/settings/README.md
+++ b/services/settings/README.md
@@ -12,12 +12,7 @@ The settings service is currently used for managing the:
 
 As an example, user profile settings that can be changed in the Web UI must be persistent.
 
-The settings service supports two different backends for persisting the data. The backend can be set via the `SETTINGS_STORE_TYPE` environment variable. Supported values are:
-
-*   `metadata`: The default. This backend persists the settings data via the `storage-system` service.
-*   `filesystem`: (deprecated) This backend persists the settings data in a directory on the local filesystem.
-  The directory can be configured with `SETTINGS_DATA_PATH`. This backend is **not** suitable for running
-  multiple intances of the `settings` service in a scale-out deployment and was therefore deprecated.
+The settings service persists the settings data via the `storage-system` service.
 
 <!--- Note: The diagramm is outdate, leaving it here for a future rework
 The diagram shows how the settings service integrates into oCIS:
@@ -37,7 +32,7 @@ graph TD
 
 ## Caching
 
-When using `SETTINGS_STORE_TYPE=metadata`, the `settings` service caches the results of queries against the storage backend to provide faster responses. The content of this cache is independent of the cache used in the `storage-system` service as it caches directory listing and settings content stored in files.
+The `settings` service caches the results of queries against the storage backend to provide faster responses. The content of this cache is independent of the cache used in the `storage-system` service as it caches directory listing and settings content stored in files.
 
 The store used for the cache can be configured using the `SETTINGS_CACHE_STORE` environment variable. Possible stores are:
   -   `memory`: Basic in-memory store and the default.
diff --git a/services/settings/pkg/config/config.go b/services/settings/pkg/config/config.go
index cc973a9852a..560060b8437 100644
--- a/services/settings/pkg/config/config.go
+++ b/services/settings/pkg/config/config.go
@@ -25,8 +25,6 @@ type Config struct {
 	GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
 	GrpcClient    client.Client         `yaml:"-"`
 
-	StoreType   string                `yaml:"store_type" env:"SETTINGS_STORE_TYPE" desc:"Store type configures the persistency driver. Supported values are 'metadata' and 'filesystem'. Note that the value 'filesystem' is considered deprecated." introductionVersion:"pre5.0"`
-	DataPath    string                `yaml:"data_path" env:"SETTINGS_DATA_PATH" desc:"The directory where the filesystem storage will store ocis settings. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/settings." introductionVersion:"pre5.0"`
 	Metadata    Metadata              `yaml:"metadata_config"`
 	BundlesPath string                `yaml:"bundles_path" env:"SETTINGS_BUNDLES_PATH" desc:"The path to a JSON file with a list of bundles. If not defined, the default bundles will be loaded." introductionVersion:"pre5.0"`
 	Bundles     []*settingsmsg.Bundle `yaml:"-"`
diff --git a/services/settings/pkg/config/defaults/defaultconfig.go b/services/settings/pkg/config/defaults/defaultconfig.go
index cc6e8c83e84..cd9ff9b618e 100644
--- a/services/settings/pkg/config/defaults/defaultconfig.go
+++ b/services/settings/pkg/config/defaults/defaultconfig.go
@@ -3,11 +3,9 @@ package defaults
 import (
 	"encoding/json"
 	"os"
-	"path"
 	"strings"
 	"time"
 
-	"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
 	"github.com/owncloud/ocis/v2/ocis-pkg/structs"
 	"github.com/owncloud/ocis/v2/services/settings/pkg/config"
 	rdefaults "github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults"
@@ -49,8 +47,6 @@ func DefaultConfig() *config.Config {
 			Addr:      "127.0.0.1:9191",
 			Namespace: "com.owncloud.api",
 		},
-		StoreType:               "metadata", // use metadata or filesystem
-		DataPath:                path.Join(defaults.BaseDataPath(), "settings"),
 		SetupDefaultAssignments: false,
 		Metadata: config.Metadata{
 			GatewayAddress: "com.owncloud.api.storage-system",
diff --git a/services/settings/pkg/service/v0/service.go b/services/settings/pkg/service/v0/service.go
index 685e6c96be4..a39a38af818 100644
--- a/services/settings/pkg/service/v0/service.go
+++ b/services/settings/pkg/service/v0/service.go
@@ -17,7 +17,6 @@ import (
 	"github.com/owncloud/ocis/v2/services/settings/pkg/config"
 	"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
 	"github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults"
-	filestore "github.com/owncloud/ocis/v2/services/settings/pkg/store/filesystem"
 	metastore "github.com/owncloud/ocis/v2/services/settings/pkg/store/metadata"
 	merrors "go-micro.dev/v4/errors"
 	"go-micro.dev/v4/metadata"
@@ -40,17 +39,7 @@ func NewService(cfg *config.Config, logger log.Logger) settings.ServiceHandler {
 		logger: logger,
 	}
 
-	switch cfg.StoreType {
-	default:
-		fallthrough
-	case "metadata":
-		service.manager = metastore.New(cfg)
-	case "filesystem":
-		fmt.Println("WARNING: filesystem store is deprecated and will be removed in the future. Please use metadata store instead.")
-		service.manager = filestore.New(cfg)
-		// TODO: if we want to further support filesystem store it should use default permissions from store/defaults/defaults.go instead using this duplicate
-		service.RegisterDefaultRoles()
-	}
+	service.manager = metastore.New(cfg)
 	return service
 }
 
@@ -101,45 +90,6 @@ func (g Service) CheckPermission(ctx context.Context, req *cs3permissions.CheckP
 	}, nil
 }
 
-// RegisterDefaultRoles composes default roles and saves them. Skipped if the roles already exist.
-func (g Service) RegisterDefaultRoles() {
-	// FIXME: we're writing default roles per service start (i.e. twice at the moment, for http and grpc server). has to happen only once.
-	for _, role := range generateBundlesDefaultRoles() {
-		bundleID := role.Extension + "." + role.Id
-		// check if the role already exists
-		bundle, _ := g.manager.ReadBundle(role.Id)
-		if bundle != nil {
-			g.logger.Debug().Str("bundleID", bundleID).Msg("bundle already exists. skipping.")
-			continue
-		}
-		// create the role
-		_, err := g.manager.WriteBundle(role)
-		if err != nil {
-			g.logger.Error().Err(err).Str("bundleID", bundleID).Msg("failed to register bundle")
-		}
-		g.logger.Debug().Str("bundleID", bundleID).Msg("successfully registered bundle")
-	}
-
-	for _, req := range generatePermissionRequests() {
-		_, err := g.manager.AddSettingToBundle(req.GetBundleId(), req.GetSetting())
-		if err != nil {
-			g.logger.Error().
-				Err(err).
-				Str("bundleID", req.GetBundleId()).
-				Interface("setting", req.GetSetting()).
-				Msg("failed to register permission")
-		}
-	}
-
-	if g.config.SetupDefaultAssignments {
-		for _, req := range g.defaultRoleAssignments() {
-			if _, err := g.manager.WriteRoleAssignment(req.AccountUuid, req.RoleId); err != nil {
-				g.logger.Error().Err(err).Msg("failed to register role assignment")
-			}
-		}
-	}
-}
-
 // TODO: check permissions on every request
 
 // SaveBundle implements the BundleServiceHandler interface
diff --git a/services/settings/pkg/service/v0/settings.go b/services/settings/pkg/service/v0/settings.go
index 40c65c59894..7618bf16362 100644
--- a/services/settings/pkg/service/v0/settings.go
+++ b/services/settings/pkg/service/v0/settings.go
@@ -1,10 +1,5 @@
 package svc
 
-import (
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
-)
-
 const (
 	// BundleUUIDRoleAdmin represents the admin role
 	BundleUUIDRoleAdmin = "71881883-1768-46bd-a24d-a356a2afdf7f"
@@ -64,567 +59,3 @@ const (
 	// ChangeLogoPermissionName is the hardcoded setting name for the change-logo permission
 	ChangeLogoPermissionName string = "change-logo"
 )
-
-// generateBundlesDefaultRoles bootstraps the default roles.
-func generateBundlesDefaultRoles() []*settingsmsg.Bundle {
-	return []*settingsmsg.Bundle{
-		generateBundleAdminRole(),
-		generateBundleSpaceAdminRole(),
-		generateBundleUserRole(),
-		generateBundleGuestRole(),
-		generateBundleProfileRequest(),
-	}
-}
-
-func generateBundleAdminRole() *settingsmsg.Bundle {
-	return &settingsmsg.Bundle{
-		Id:          BundleUUIDRoleAdmin,
-		Name:        "admin",
-		Type:        settingsmsg.Bundle_TYPE_ROLE,
-		Extension:   "ocis-roles",
-		DisplayName: "Admin",
-		Resource: &settingsmsg.Resource{
-			Type: settingsmsg.Resource_TYPE_SYSTEM,
-		},
-		Settings: []*settingsmsg.Setting{},
-	}
-}
-
-func generateBundleSpaceAdminRole() *settingsmsg.Bundle {
-	return &settingsmsg.Bundle{
-		Id:          BundleUUIDRoleSpaceAdmin,
-		Name:        "spaceadmin",
-		Type:        settingsmsg.Bundle_TYPE_ROLE,
-		Extension:   "ocis-roles",
-		DisplayName: "Space Admin",
-		Resource: &settingsmsg.Resource{
-			Type: settingsmsg.Resource_TYPE_SYSTEM,
-		},
-		Settings: []*settingsmsg.Setting{},
-	}
-}
-
-func generateBundleUserRole() *settingsmsg.Bundle {
-	return &settingsmsg.Bundle{
-		Id:          BundleUUIDRoleUser,
-		Name:        "user",
-		Type:        settingsmsg.Bundle_TYPE_ROLE,
-		Extension:   "ocis-roles",
-		DisplayName: "User",
-		Resource: &settingsmsg.Resource{
-			Type: settingsmsg.Resource_TYPE_SYSTEM,
-		},
-		Settings: []*settingsmsg.Setting{},
-	}
-}
-
-func generateBundleGuestRole() *settingsmsg.Bundle {
-	return &settingsmsg.Bundle{
-		Id:          BundleUUIDRoleGuest,
-		Name:        "guest",
-		Type:        settingsmsg.Bundle_TYPE_ROLE,
-		Extension:   "ocis-roles",
-		DisplayName: "Guest",
-		Resource: &settingsmsg.Resource{
-			Type: settingsmsg.Resource_TYPE_SYSTEM,
-		},
-		Settings: []*settingsmsg.Setting{},
-	}
-}
-
-var languageSetting = settingsmsg.Setting_SingleChoiceValue{
-	SingleChoiceValue: &settingsmsg.SingleChoiceList{
-		Options: []*settingsmsg.ListOption{
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "bg",
-					},
-				},
-				DisplayValue: "български",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "cs",
-					},
-				},
-				DisplayValue: "Czech",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "de",
-					},
-				},
-				DisplayValue: "Deutsch",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "en",
-					},
-				},
-				DisplayValue: "English",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "es",
-					},
-				},
-				DisplayValue: "Español",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "fr",
-					},
-				},
-				DisplayValue: "Français",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "gl",
-					},
-				},
-				DisplayValue: "Galego",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "it",
-					},
-				},
-				DisplayValue: "Italiano",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "nl",
-					},
-				},
-				DisplayValue: "Nederlands",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "ko",
-					},
-				},
-				DisplayValue: "한국어",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "sq",
-					},
-				},
-				DisplayValue: "Shqipja",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "sv",
-					},
-				},
-				DisplayValue: "Svenska",
-			},
-			{
-				Value: &settingsmsg.ListOptionValue{
-					Option: &settingsmsg.ListOptionValue_StringValue{
-						StringValue: "tr",
-					},
-				},
-				DisplayValue: "Türkçe",
-			},
-		},
-	},
-}
-
-func generateBundleProfileRequest() *settingsmsg.Bundle {
-	return &settingsmsg.Bundle{
-		Id:        "2a506de7-99bd-4f0d-994e-c38e72c28fd9",
-		Name:      "profile",
-		Extension: "ocis-accounts",
-		Type:      settingsmsg.Bundle_TYPE_DEFAULT,
-		Resource: &settingsmsg.Resource{
-			Type: settingsmsg.Resource_TYPE_SYSTEM,
-		},
-		DisplayName: "Profile",
-		Settings: []*settingsmsg.Setting{
-			{
-				Id:          SettingUUIDProfileLanguage,
-				Name:        "language",
-				DisplayName: "Language",
-				Description: "User language",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_USER,
-				},
-				Value: &languageSetting,
-			},
-		},
-	}
-}
-
-func generatePermissionRequests() []*settingssvc.AddSettingToBundleRequest {
-	return []*settingssvc.AddSettingToBundleRequest{
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          RoleManagementPermissionID,
-				Name:        RoleManagementPermissionName,
-				DisplayName: "Role Management",
-				Description: "This permission gives full access to everything that is related to role management.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_USER,
-					Id:   "all",
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          SettingsManagementPermissionID,
-				Name:        SettingsManagementPermissionName,
-				DisplayName: "Settings Management",
-				Description: "This permission gives full access to everything that is related to settings management.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_USER,
-					Id:   "all",
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          "7d81f103-0488-4853-bce5-98dcce36d649",
-				Name:        "language-readwrite",
-				DisplayName: "Permission to read and set the language (anyone)",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SETTING,
-					Id:   SettingUUIDProfileLanguage,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleUser,
-			Setting: &settingsmsg.Setting{
-				Id:          "640e00d2-4df8-41bd-b1c2-9f30a01e0e99",
-				Name:        "language-readwrite",
-				DisplayName: "Permission to read and set the language (self)",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SETTING,
-					Id:   SettingUUIDProfileLanguage,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleGuest,
-			Setting: &settingsmsg.Setting{
-				Id:          "ca878636-8b1a-4fae-8282-8617a4c13597",
-				Name:        "language-readwrite",
-				DisplayName: "Permission to read and set the language (self)",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SETTING,
-					Id:   SettingUUIDProfileLanguage,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          AccountManagementPermissionID,
-				Name:        AccountManagementPermissionName,
-				DisplayName: "Account Management",
-				Description: "This permission gives full access to everything that is related to account management.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_USER,
-					Id:   "all",
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          GroupManagementPermissionID,
-				Name:        GroupManagementPermissionName,
-				DisplayName: "Group Management",
-				Description: "This permission gives full access to everything that is related to group management.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_GROUP,
-					Id:   "all",
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleUser,
-			Setting: &settingsmsg.Setting{
-				Id:          SelfManagementPermissionID,
-				Name:        SelfManagementPermissionName,
-				DisplayName: "Self Management",
-				Description: "This permission gives access to self management.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_USER,
-					Id:   "me",
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          SetSpaceQuotaPermissionID,
-				Name:        SetSpaceQuotaPermissionName,
-				DisplayName: "Set Space Quota",
-				Description: "This permission allows managing space quotas.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleUser,
-			Setting: &settingsmsg.Setting{
-				Id:          CreateSpacePermissionID,
-				Name:        CreateSpacePermissionName,
-				DisplayName: "Create own Space",
-				Description: "This permission allows creating a space owned by the current user.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM, // TODO resource type space? self? me? own?
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_CREATE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          CreateSpacePermissionID,
-				Name:        CreateSpacePermissionName,
-				DisplayName: "Create Space",
-				Description: "This permission allows creating new spaces.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          ListAllSpacesPermissionID,
-				Name:        ListAllSpacesPermissionName,
-				DisplayName: "List All Spaces",
-				Description: "This permission allows list all spaces.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READ,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          ChangeLogoPermissionID,
-				Name:        ChangeLogoPermissionName,
-				DisplayName: "Change logo",
-				Description: "This permission permits to change the system logo.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleSpaceAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          CreateSpacePermissionID,
-				Name:        CreateSpacePermissionName,
-				DisplayName: "Create Space",
-				Description: "This permission allows creating new spaces.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleSpaceAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          SetSpaceQuotaPermissionID,
-				Name:        SetSpaceQuotaPermissionName,
-				DisplayName: "Set Space Quota",
-				Description: "This permission allows managing space quotas.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleSpaceAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          ListAllSpacesPermissionID,
-				Name:        ListAllSpacesPermissionName,
-				DisplayName: "List All Spaces",
-				Description: "This permission allows list all spaces.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SYSTEM,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READ,
-						Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleSpaceAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          "640e00d2-4df8-41bd-b1c2-9f30a01e0e99",
-				Name:        "language-readwrite",
-				DisplayName: "Permission to read and set the language (self)",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_SETTING,
-					Id:   SettingUUIDProfileLanguage,
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
-					},
-				},
-			},
-		},
-		{
-			BundleId: BundleUUIDRoleSpaceAdmin,
-			Setting: &settingsmsg.Setting{
-				Id:          SelfManagementPermissionID,
-				Name:        SelfManagementPermissionName,
-				DisplayName: "Self Management",
-				Description: "This permission gives access to self management.",
-				Resource: &settingsmsg.Resource{
-					Type: settingsmsg.Resource_TYPE_USER,
-					Id:   "me",
-				},
-				Value: &settingsmsg.Setting_PermissionValue{
-					PermissionValue: &settingsmsg.Permission{
-						Operation:  settingsmsg.Permission_OPERATION_READWRITE,
-						Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
-					},
-				},
-			},
-		},
-	}
-}
-
-func (g Service) defaultRoleAssignments() []*settingsmsg.UserRoleAssignment {
-	return []*settingsmsg.UserRoleAssignment{
-		// default admin users
-		{
-			AccountUuid: g.config.AdminUserID,
-			RoleId:      BundleUUIDRoleAdmin,
-		},
-		// default users with role "user"
-		{
-			AccountUuid: "4c510ada-c86b-4815-8820-42cdf82c3d51", // demo user "einstein"
-			RoleId:      BundleUUIDRoleUser,
-		}, {
-			AccountUuid: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c", // demo user "marie"
-			RoleId:      BundleUUIDRoleUser,
-		},
-		// default users with role "spaceadmin"
-		{
-			AccountUuid: "058bff95-6708-4fe5-91e4-9ea3d377588b", // demo user "moss"
-			RoleId:      BundleUUIDRoleSpaceAdmin,
-		}, {
-			AccountUuid: "534bb038-6f9d-4093-946f-133be61fa4e7", // demo user "katherine"
-			RoleId:      BundleUUIDRoleSpaceAdmin,
-		},
-	}
-}
diff --git a/services/settings/pkg/store/filesystem/assignments.go b/services/settings/pkg/store/filesystem/assignments.go
deleted file mode 100644
index 7e997c9d863..00000000000
--- a/services/settings/pkg/store/filesystem/assignments.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Package store implements the go-micro store interface
-package store
-
-import (
-	"os"
-	"path/filepath"
-
-	"github.com/gofrs/uuid"
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-)
-
-// ListRoleAssignments loads and returns all role assignments matching the given assignment identifier.
-func (s Store) ListRoleAssignments(accountUUID string) ([]*settingsmsg.UserRoleAssignment, error) {
-	var records []*settingsmsg.UserRoleAssignment
-	assignmentsFolder := s.buildFolderPathForRoleAssignments(false)
-	assignmentFiles, err := os.ReadDir(assignmentsFolder)
-	if err != nil {
-		return nil, nil
-	}
-
-	for _, assignmentFile := range assignmentFiles {
-		record := settingsmsg.UserRoleAssignment{}
-		err = s.parseRecordFromFile(&record, filepath.Join(assignmentsFolder, assignmentFile.Name()))
-		if err == nil {
-			if record.AccountUuid == accountUUID {
-				records = append(records, &record)
-			}
-		}
-	}
-
-	return records, nil
-}
-
-// WriteRoleAssignment appends the given role assignment to the existing assignments of the respective account.
-func (s Store) WriteRoleAssignment(accountUUID, roleID string) (*settingsmsg.UserRoleAssignment, error) {
-	// as per https://github.com/owncloud/product/issues/103 "Each user can have exactly one role"
-	list, err := s.ListRoleAssignments(accountUUID)
-	if err != nil {
-		return nil, err
-	}
-	if len(list) > 0 {
-		filePath := s.buildFilePathForRoleAssignment(list[0].Id, true)
-		if err := os.Remove(filePath); err != nil {
-			return nil, err
-		}
-	}
-
-	assignment := &settingsmsg.UserRoleAssignment{
-		Id:          uuid.Must(uuid.NewV4()).String(),
-		AccountUuid: accountUUID,
-		RoleId:      roleID,
-	}
-	filePath := s.buildFilePathForRoleAssignment(assignment.Id, true)
-	if err := s.writeRecordToFile(assignment, filePath); err != nil {
-		return nil, err
-	}
-
-	s.Logger.Debug().Msgf("request contents written to file: %v", filePath)
-	return assignment, nil
-}
-
-// RemoveRoleAssignment deletes the given role assignment from the existing assignments of the respective account.
-func (s Store) RemoveRoleAssignment(assignmentID string) error {
-	filePath := s.buildFilePathForRoleAssignment(assignmentID, false)
-	return os.Remove(filePath)
-}
diff --git a/services/settings/pkg/store/filesystem/bundles.go b/services/settings/pkg/store/filesystem/bundles.go
deleted file mode 100644
index f0e5749c84a..00000000000
--- a/services/settings/pkg/store/filesystem/bundles.go
+++ /dev/null
@@ -1,181 +0,0 @@
-// Package store implements the go-micro store interface
-package store
-
-import (
-	"errors"
-	"fmt"
-	"os"
-	"path/filepath"
-	"sync"
-
-	"github.com/gofrs/uuid"
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-	"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
-)
-
-var m = &sync.RWMutex{}
-
-// ListBundles returns all bundles in the dataPath folder that match the given type.
-func (s Store) ListBundles(bundleType settingsmsg.Bundle_Type, bundleIDs []string) ([]*settingsmsg.Bundle, error) {
-	// FIXME: list requests should be ran against a cache, not FS
-	m.RLock()
-	defer m.RUnlock()
-
-	bundlesFolder := s.buildFolderPathForBundles(false)
-	bundleFiles, err := os.ReadDir(bundlesFolder)
-	if err != nil {
-		return nil, err
-	}
-
-	records := make([]*settingsmsg.Bundle, 0, len(bundleFiles))
-	for _, bundleFile := range bundleFiles {
-		record := settingsmsg.Bundle{}
-		err = s.parseRecordFromFile(&record, filepath.Join(bundlesFolder, bundleFile.Name()))
-		if err != nil {
-			s.Logger.Warn().Msgf("error reading %v", bundleFile)
-			continue
-		}
-		if record.Type != bundleType {
-			continue
-		}
-		if len(bundleIDs) > 0 && !containsStr(record.Id, bundleIDs) {
-			continue
-		}
-		records = append(records, &record)
-	}
-
-	return records, nil
-}
-
-// containsStr checks if the strs slice contains str
-func containsStr(str string, strs []string) bool {
-	for _, s := range strs {
-		if s == str {
-			return true
-		}
-	}
-	return false
-}
-
-// ReadBundle tries to find a bundle by the given id within the dataPath.
-func (s Store) ReadBundle(bundleID string) (*settingsmsg.Bundle, error) {
-	m.RLock()
-	defer m.RUnlock()
-
-	filePath := s.buildFilePathForBundle(bundleID, false)
-	record := settingsmsg.Bundle{}
-	if err := s.parseRecordFromFile(&record, filePath); err != nil {
-		return nil, err
-	}
-
-	s.Logger.Debug().Msgf("read contents from file: %v", filePath)
-	return &record, nil
-}
-
-// ReadSetting tries to find a setting by the given id within the dataPath.
-func (s Store) ReadSetting(settingID string) (*settingsmsg.Setting, error) {
-	m.RLock()
-	defer m.RUnlock()
-
-	bundles, err := s.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, []string{})
-	if err != nil {
-		return nil, err
-	}
-	for _, bundle := range bundles {
-		for _, setting := range bundle.Settings {
-			if setting.Id == settingID {
-				return setting, nil
-			}
-		}
-	}
-	return nil, fmt.Errorf("could not read setting: %v", settingID)
-}
-
-// WriteBundle writes the given record into a file within the dataPath.
-func (s Store) WriteBundle(record *settingsmsg.Bundle) (*settingsmsg.Bundle, error) {
-	// FIXME: locking should happen on the file here, not globally.
-	m.Lock()
-	defer m.Unlock()
-	if record.Id == "" {
-		record.Id = uuid.Must(uuid.NewV4()).String()
-	}
-	filePath := s.buildFilePathForBundle(record.Id, true)
-	if err := s.writeRecordToFile(record, filePath); err != nil {
-		return nil, err
-	}
-
-	s.Logger.Debug().Msgf("request contents written to file: %v", filePath)
-	return record, nil
-}
-
-// AddSettingToBundle adds the given setting to the bundle with the given bundleID.
-func (s Store) AddSettingToBundle(bundleID string, setting *settingsmsg.Setting) (*settingsmsg.Setting, error) {
-	bundle, err := s.ReadBundle(bundleID)
-	if err != nil {
-		if !errors.Is(err, settings.ErrNotFound) {
-			return nil, err
-		}
-		bundle = new(settingsmsg.Bundle)
-		bundle.Id = bundleID
-		bundle.Type = settingsmsg.Bundle_TYPE_DEFAULT
-	}
-	if setting.Id == "" {
-		setting.Id = uuid.Must(uuid.NewV4()).String()
-	}
-	setSetting(bundle, setting)
-	_, err = s.WriteBundle(bundle)
-	if err != nil {
-		return nil, err
-	}
-	return setting, nil
-}
-
-// RemoveSettingFromBundle removes the setting from the bundle with the given ids.
-func (s Store) RemoveSettingFromBundle(bundleID string, settingID string) error {
-	bundle, err := s.ReadBundle(bundleID)
-	if err != nil {
-		return err
-	}
-	if ok := removeSetting(bundle, settingID); ok {
-		if _, err := s.WriteBundle(bundle); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// indexOfSetting finds the index of the given setting within the given bundle.
-// returns -1 if the setting was not found.
-func indexOfSetting(bundle *settingsmsg.Bundle, settingID string) int {
-	for index := range bundle.Settings {
-		s := bundle.Settings[index]
-		if s.Id == settingID {
-			return index
-		}
-	}
-	return -1
-}
-
-// setSetting will append or overwrite the given setting within the given bundle
-func setSetting(bundle *settingsmsg.Bundle, setting *settingsmsg.Setting) {
-	m.Lock()
-	defer m.Unlock()
-	index := indexOfSetting(bundle, setting.Id)
-	if index == -1 {
-		bundle.Settings = append(bundle.Settings, setting)
-	} else {
-		bundle.Settings[index] = setting
-	}
-}
-
-// removeSetting will remove the given setting from the given bundle
-func removeSetting(bundle *settingsmsg.Bundle, settingID string) bool {
-	m.Lock()
-	defer m.Unlock()
-	index := indexOfSetting(bundle, settingID)
-	if index == -1 {
-		return false
-	}
-	bundle.Settings = append(bundle.Settings[:index], bundle.Settings[index+1:]...)
-	return true
-}
diff --git a/services/settings/pkg/store/filesystem/io.go b/services/settings/pkg/store/filesystem/io.go
deleted file mode 100644
index a1b0f832d3a..00000000000
--- a/services/settings/pkg/store/filesystem/io.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package store
-
-import (
-	"fmt"
-	"io"
-	"os"
-
-	"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
-	"google.golang.org/protobuf/encoding/protojson"
-	"google.golang.org/protobuf/proto"
-)
-
-// Unmarshal file into record
-func (s Store) parseRecordFromFile(record proto.Message, filePath string) error {
-	_, err := os.Stat(filePath)
-	if err != nil {
-		return fmt.Errorf("%q: %w", filePath, settings.ErrNotFound)
-	}
-
-	file, err := os.Open(filePath)
-	if err != nil {
-		return err
-	}
-	defer file.Close()
-
-	b, err := io.ReadAll(file)
-	if err != nil {
-		return err
-	}
-
-	if len(b) == 0 {
-		return fmt.Errorf("%q: %w", filePath, settings.ErrNotFound)
-	}
-
-	if err := protojson.Unmarshal(b, record); err != nil {
-		return err
-	}
-	return nil
-}
-
-// Marshal record into file
-func (s Store) writeRecordToFile(record proto.Message, filePath string) error {
-	file, err := os.Create(filePath)
-	if err != nil {
-		return err
-	}
-	defer file.Close()
-
-	v, err := protojson.Marshal(record)
-	if err != nil {
-		return err
-	}
-
-	_, err = file.Write(v)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
diff --git a/services/settings/pkg/store/filesystem/paths.go b/services/settings/pkg/store/filesystem/paths.go
deleted file mode 100644
index d6d21e89c77..00000000000
--- a/services/settings/pkg/store/filesystem/paths.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package store
-
-import (
-	"os"
-	"path/filepath"
-)
-
-const folderNameBundles = "bundles"
-const folderNameValues = "values"
-const folderNameAssignments = "assignments"
-
-// buildFolderPathForBundles builds the folder path for storing settings bundles. If mkdir is true, folders in the path will be created if necessary.
-func (s Store) buildFolderPathForBundles(mkdir bool) string {
-	folderPath := filepath.Join(s.dataPath, folderNameBundles)
-	if mkdir {
-		s.ensureFolderExists(folderPath)
-	}
-	return folderPath
-}
-
-// buildFilePathForBundle builds a unique file name from the given params. If mkdir is true, folders in the path will be created if necessary.
-func (s Store) buildFilePathForBundle(bundleID string, mkdir bool) string {
-	extensionFolder := s.buildFolderPathForBundles(mkdir)
-	return filepath.Join(extensionFolder, bundleID+".json")
-}
-
-// buildFolderPathForValues builds the folder path for storing settings values. If mkdir is true, folders in the path will be created if necessary.
-func (s Store) buildFolderPathForValues(mkdir bool) string {
-	folderPath := filepath.Join(s.dataPath, folderNameValues)
-	if mkdir {
-		s.ensureFolderExists(folderPath)
-	}
-	return folderPath
-}
-
-// buildFilePathForValue builds a unique file name from the given params. If mkdir is true, folders in the path will be created if necessary.
-func (s Store) buildFilePathForValue(valueID string, mkdir bool) string {
-	extensionFolder := s.buildFolderPathForValues(mkdir)
-	return filepath.Join(extensionFolder, valueID+".json")
-}
-
-// buildFolderPathForRoleAssignments builds the folder path for storing role assignments. If mkdir is true, folders in the path will be created if necessary.
-func (s Store) buildFolderPathForRoleAssignments(mkdir bool) string {
-	roleAssignmentsFolder := filepath.Join(s.dataPath, folderNameAssignments)
-	if mkdir {
-		s.ensureFolderExists(roleAssignmentsFolder)
-	}
-	return roleAssignmentsFolder
-}
-
-// buildFilePathForRoleAssignment builds a unique file name from the given params. If mkdir is true, folders in the path will be created if necessary.
-func (s Store) buildFilePathForRoleAssignment(assignmentID string, mkdir bool) string {
-	roleAssignmentsFolder := s.buildFolderPathForRoleAssignments(mkdir)
-	return filepath.Join(roleAssignmentsFolder, assignmentID+".json")
-}
-
-// ensureFolderExists checks if the given path is an existing folder and creates one if not existing
-func (s Store) ensureFolderExists(path string) {
-	if _, err := os.Stat(path); os.IsNotExist(err) {
-		err = os.MkdirAll(path, 0700)
-		if err != nil {
-			s.Logger.Err(err).Msgf("Error creating folder %v", path)
-		}
-	}
-}
diff --git a/services/settings/pkg/store/filesystem/permissions.go b/services/settings/pkg/store/filesystem/permissions.go
deleted file mode 100644
index 1c03e643871..00000000000
--- a/services/settings/pkg/store/filesystem/permissions.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package store
-
-import (
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-	"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
-	"github.com/owncloud/ocis/v2/services/settings/pkg/util"
-)
-
-// ListPermissionsByResource collects all permissions from the provided roleIDs that match the requested resource
-func (s Store) ListPermissionsByResource(resource *settingsmsg.Resource, roleIDs []string) ([]*settingsmsg.Permission, error) {
-	records := make([]*settingsmsg.Permission, 0)
-	for _, roleID := range roleIDs {
-		role, err := s.ReadBundle(roleID)
-		if err != nil {
-			s.Logger.Debug().Str("roleID", roleID).Msg("role not found, skipping")
-			continue
-		}
-		records = append(records, extractPermissionsByResource(resource, role)...)
-	}
-	return records, nil
-}
-
-// ReadPermissionByID finds the permission in the roles, specified by the provided roleIDs
-func (s Store) ReadPermissionByID(permissionID string, roleIDs []string) (*settingsmsg.Permission, error) {
-	for _, roleID := range roleIDs {
-		role, err := s.ReadBundle(roleID)
-		if err != nil {
-			s.Logger.Debug().Str("roleID", roleID).Msg("role not found, skipping")
-			continue
-		}
-		for _, permission := range role.Settings {
-			if permission.Id == permissionID {
-				if value, ok := permission.Value.(*settingsmsg.Setting_PermissionValue); ok {
-					return value.PermissionValue, nil
-				}
-			}
-		}
-	}
-	return nil, nil
-}
-
-// ReadPermissionByName finds the permission in the roles, specified by the provided roleIDs
-func (s Store) ReadPermissionByName(name string, roleIDs []string) (*settingsmsg.Permission, error) {
-	for _, roleID := range roleIDs {
-		role, err := s.ReadBundle(roleID)
-		if err != nil {
-			s.Logger.Debug().Str("roleID", roleID).Msg("role not found, skipping")
-			continue
-		}
-		for _, permission := range role.Settings {
-			if permission.Name == name {
-				if value, ok := permission.Value.(*settingsmsg.Setting_PermissionValue); ok {
-					return value.PermissionValue, nil
-				}
-			}
-		}
-	}
-	return nil, settings.ErrNotFound
-}
-
-// extractPermissionsByResource collects all permissions from the provided role that match the requested resource
-func extractPermissionsByResource(resource *settingsmsg.Resource, role *settingsmsg.Bundle) []*settingsmsg.Permission {
-	permissions := make([]*settingsmsg.Permission, 0)
-	for _, setting := range role.Settings {
-		if value, ok := setting.Value.(*settingsmsg.Setting_PermissionValue); ok {
-			if util.IsResourceMatched(setting.Resource, resource) {
-				permissions = append(permissions, value.PermissionValue)
-			}
-		}
-	}
-	return permissions
-}
diff --git a/services/settings/pkg/store/filesystem/staticcheck.conf b/services/settings/pkg/store/filesystem/staticcheck.conf
deleted file mode 100644
index 5120a177a3c..00000000000
--- a/services/settings/pkg/store/filesystem/staticcheck.conf
+++ /dev/null
@@ -1,1 +0,0 @@
-checks = ["all", "-ST1003", "-ST1000", "-SA1019"]
\ No newline at end of file
diff --git a/services/settings/pkg/store/filesystem/store.go b/services/settings/pkg/store/filesystem/store.go
deleted file mode 100644
index 970e3e73ffc..00000000000
--- a/services/settings/pkg/store/filesystem/store.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Package store implements the go-micro store interface
-package store
-
-import (
-	"os"
-
-	olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
-	"github.com/owncloud/ocis/v2/services/settings/pkg/config"
-	"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
-)
-
-var (
-	// Name is the default name for the settings store
-	Name        = "ocis-settings"
-	managerName = "filesystem"
-)
-
-// Store interacts with the filesystem to manage settings information
-type Store struct {
-	dataPath string
-	Logger   olog.Logger
-}
-
-// New creates a new store
-func New(cfg *config.Config) settings.Manager {
-	s := Store{
-		//Logger: olog.NewLogger(
-		//	olog.Color(cfg.Log.Color),
-		//	olog.Pretty(cfg.Log.Pretty),
-		//	olog.Level(cfg.Log.Level),
-		//	olog.File(cfg.Log.File),
-		//),
-	}
-
-	if _, err := os.Stat(cfg.DataPath); err != nil {
-		s.Logger.Info().Msgf("creating container on %v", cfg.DataPath)
-		err = os.MkdirAll(cfg.DataPath, 0700)
-
-		if err != nil {
-			s.Logger.Err(err).Msgf("providing container on %v", cfg.DataPath)
-		}
-	}
-
-	s.dataPath = cfg.DataPath
-	return &s
-}
-
-func init() {
-	settings.Registry[managerName] = New
-}
diff --git a/services/settings/pkg/store/filesystem/values.go b/services/settings/pkg/store/filesystem/values.go
deleted file mode 100644
index 230a0505593..00000000000
--- a/services/settings/pkg/store/filesystem/values.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// Package store implements the go-micro store interface
-package store
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-
-	"github.com/gofrs/uuid"
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-)
-
-// ListValues reads all values that match the given bundleId and accountUUID.
-// If the bundleId is empty, it's ignored for filtering.
-// If the accountUUID is empty, only values with empty accountUUID are returned.
-// If the accountUUID is not empty, values with an empty or with a matching accountUUID are returned.
-func (s Store) ListValues(bundleID, accountUUID string) ([]*settingsmsg.Value, error) {
-	valuesFolder := s.buildFolderPathForValues(false)
-	valueFiles, err := os.ReadDir(valuesFolder)
-	if err != nil {
-		return nil, err
-	}
-
-	records := make([]*settingsmsg.Value, 0, len(valueFiles))
-	for _, valueFile := range valueFiles {
-		record := settingsmsg.Value{}
-		err := s.parseRecordFromFile(&record, filepath.Join(valuesFolder, valueFile.Name()))
-		if err != nil {
-			s.Logger.Warn().Msgf("error reading %v", valueFile)
-			continue
-		}
-		if bundleID != "" && record.BundleId != bundleID {
-			continue
-		}
-		// if requested accountUUID empty -> fetch all system level values
-		if accountUUID == "" && record.AccountUuid != "" {
-			continue
-		}
-		// if requested accountUUID empty -> fetch all individual + all system level values
-		if accountUUID != "" && record.AccountUuid != "" && record.AccountUuid != accountUUID {
-			continue
-		}
-		records = append(records, &record)
-	}
-
-	return records, nil
-}
-
-// ReadValue tries to find a value by the given valueId within the dataPath
-func (s Store) ReadValue(valueID string) (*settingsmsg.Value, error) {
-	filePath := s.buildFilePathForValue(valueID, false)
-	record := settingsmsg.Value{}
-	if err := s.parseRecordFromFile(&record, filePath); err != nil {
-		return nil, err
-	}
-
-	s.Logger.Debug().Msgf("read contents from file: %v", filePath)
-	return &record, nil
-}
-
-// ReadValueByUniqueIdentifiers tries to find a value given a set of unique identifiers
-func (s Store) ReadValueByUniqueIdentifiers(accountUUID, settingID string) (*settingsmsg.Value, error) {
-	valuesFolder := s.buildFolderPathForValues(false)
-	files, err := os.ReadDir(valuesFolder)
-	if err != nil {
-		return nil, err
-	}
-	for i := range files {
-		if !files[i].IsDir() {
-			r := settingsmsg.Value{}
-			s.Logger.Debug().Msgf("reading contents from file: %v", filepath.Join(valuesFolder, files[i].Name()))
-			if err := s.parseRecordFromFile(&r, filepath.Join(valuesFolder, files[i].Name())); err != nil {
-				s.Logger.Debug().Msgf("match found: %v", filepath.Join(valuesFolder, files[i].Name()))
-				return nil, err
-			}
-
-			// if value saved without accountUUID, then it's a global value
-			if r.AccountUuid == "" && r.SettingId == settingID {
-				return &r, nil
-			}
-			// if value saved with accountUUID, then it's a user specific value
-			if r.AccountUuid == accountUUID && r.SettingId == settingID {
-				return &r, nil
-			}
-		}
-	}
-
-	return nil, fmt.Errorf("could not read value by settingID=%v and accountID=%v", settingID, accountUUID)
-}
-
-// WriteValue writes the given value into a file within the dataPath
-func (s Store) WriteValue(value *settingsmsg.Value) (*settingsmsg.Value, error) {
-	s.Logger.Debug().Str("value", value.String()).Msg("writing value")
-	if value.Id == "" {
-		value.Id = uuid.Must(uuid.NewV4()).String()
-	}
-
-	// modify value depending on associated resource
-	if value.Resource.Type == settingsmsg.Resource_TYPE_SYSTEM {
-		value.AccountUuid = ""
-	}
-
-	// write the value
-	filePath := s.buildFilePathForValue(value.Id, true)
-	if err := s.writeRecordToFile(value, filePath); err != nil {
-		return nil, err
-	}
-	return value, nil
-}
diff --git a/services/settings/pkg/store/registry.go b/services/settings/pkg/store/registry.go
index 7c777159826..3b3471d98d4 100644
--- a/services/settings/pkg/store/registry.go
+++ b/services/settings/pkg/store/registry.go
@@ -2,6 +2,5 @@ package store
 
 import (
 	// init filesystem store
-	_ "github.com/owncloud/ocis/v2/services/settings/pkg/store/filesystem"
 	_ "github.com/owncloud/ocis/v2/services/settings/pkg/store/metadata"
 )
diff --git a/vendor/go.etcd.io/bbolt/.go-version b/vendor/go.etcd.io/bbolt/.go-version
new file mode 100644
index 00000000000..f124bfa1554
--- /dev/null
+++ b/vendor/go.etcd.io/bbolt/.go-version
@@ -0,0 +1,1 @@
+1.21.9
diff --git a/vendor/go.etcd.io/bbolt/README.md b/vendor/go.etcd.io/bbolt/README.md
index 2be669a60a1..495a93ef8f3 100644
--- a/vendor/go.etcd.io/bbolt/README.md
+++ b/vendor/go.etcd.io/bbolt/README.md
@@ -421,10 +421,19 @@ Prev()   Move to the previous key.
 ```
 
 Each of those functions has a return signature of `(key []byte, value []byte)`.
-When you have iterated to the end of the cursor then `Next()` will return a
-`nil` key.  You must seek to a position using `First()`, `Last()`, or `Seek()`
-before calling `Next()` or `Prev()`. If you do not seek to a position then
-these functions will return a `nil` key.
+You must seek to a position using `First()`, `Last()`, or `Seek()` before calling
+`Next()` or `Prev()`. If you do not seek to a position then these functions will
+return a `nil` key.
+
+When you have iterated to the end of the cursor, then `Next()` will return a
+`nil` key and the cursor still points to the last element if present. When you
+have iterated to the beginning of the cursor, then `Prev()` will return a `nil`
+key and the cursor still points to the first element if present.
+
+If you remove key/value pairs during iteration, the cursor may automatically
+move to the next position if present in current node each time removing a key.
+When you call `c.Next()` after removing a key, it may skip one key/value pair.
+Refer to [pull/611](https://github.com/etcd-io/bbolt/pull/611) to get more detailed info.
 
 During iteration, if the key is non-`nil` but the value is `nil`, that means
 the key refers to a bucket rather than a value.  Use `Bucket.Bucket()` to
@@ -850,6 +859,12 @@ Here are a few things to note when evaluating and using Bolt:
   to grow. However, it's important to note that deleting large chunks of data
   will not allow you to reclaim that space on disk.
 
+* Removing key/values pairs in a bucket during iteration on the bucket using
+  cursor may not work properly. Each time when removing a key/value pair, the
+  cursor may automatically move to the next position if present. When users
+  call `c.Next()` after removing a key, it may skip one key/value pair.
+  Refer to https://github.com/etcd-io/bbolt/pull/611 for more detailed info.
+
   For more information on page allocation, [see this comment][page-allocation].
 
 [page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638
diff --git a/vendor/go.etcd.io/bbolt/cursor.go b/vendor/go.etcd.io/bbolt/cursor.go
index 5dafb0cac3a..bbfd92a9bc1 100644
--- a/vendor/go.etcd.io/bbolt/cursor.go
+++ b/vendor/go.etcd.io/bbolt/cursor.go
@@ -71,7 +71,7 @@ func (c *Cursor) Last() (key []byte, value []byte) {
 
 	// If this is an empty page (calling Delete may result in empty pages)
 	// we call prev to find the last page that is not empty
-	for len(c.stack) > 0 && c.stack[len(c.stack)-1].count() == 0 {
+	for len(c.stack) > 1 && c.stack[len(c.stack)-1].count() == 0 {
 		c.prev()
 	}
 
@@ -254,6 +254,15 @@ func (c *Cursor) prev() (key []byte, value []byte, flags uint32) {
 			elem.index--
 			break
 		}
+		// If we've hit the beginning, we should stop moving the cursor,
+		// and stay at the first element, so that users can continue to
+		// iterate over the elements in reverse direction by calling `Next`.
+		// We should return nil in such case.
+		// Refer to https://github.com/etcd-io/bbolt/issues/733
+		if len(c.stack) == 1 {
+			c.first()
+			return nil, nil, 0
+		}
 		c.stack = c.stack[:i]
 	}
 
diff --git a/vendor/go.etcd.io/bbolt/freelist.go b/vendor/go.etcd.io/bbolt/freelist.go
index 50f2d0e174d..61d43f81b46 100644
--- a/vendor/go.etcd.io/bbolt/freelist.go
+++ b/vendor/go.etcd.io/bbolt/freelist.go
@@ -282,9 +282,8 @@ func (f *freelist) read(p *page) {
 	if count == 0 {
 		f.ids = nil
 	} else {
-		var ids []pgid
-		data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(ids[0]), idx)
-		unsafeSlice(unsafe.Pointer(&ids), data, count)
+		data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(pgid(0)), idx)
+		ids := unsafe.Slice((*pgid)(data), count)
 
 		// copy the ids, so we don't modify on the freelist page directly
 		idsCopy := make([]pgid, count)
@@ -322,15 +321,13 @@ func (f *freelist) write(p *page) error {
 		p.count = uint16(l)
 	} else if l < 0xFFFF {
 		p.count = uint16(l)
-		var ids []pgid
 		data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
-		unsafeSlice(unsafe.Pointer(&ids), data, l)
+		ids := unsafe.Slice((*pgid)(data), l)
 		f.copyall(ids)
 	} else {
 		p.count = 0xFFFF
-		var ids []pgid
 		data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
-		unsafeSlice(unsafe.Pointer(&ids), data, l+1)
+		ids := unsafe.Slice((*pgid)(data), l+1)
 		ids[0] = pgid(l)
 		f.copyall(ids[1:])
 	}
diff --git a/vendor/go.etcd.io/bbolt/page.go b/vendor/go.etcd.io/bbolt/page.go
index 379645c97fd..bb081b031e6 100644
--- a/vendor/go.etcd.io/bbolt/page.go
+++ b/vendor/go.etcd.io/bbolt/page.go
@@ -74,9 +74,8 @@ func (p *page) leafPageElements() []leafPageElement {
 	if p.count == 0 {
 		return nil
 	}
-	var elems []leafPageElement
 	data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
-	unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
+	elems := unsafe.Slice((*leafPageElement)(data), int(p.count))
 	return elems
 }
 
@@ -91,9 +90,8 @@ func (p *page) branchPageElements() []branchPageElement {
 	if p.count == 0 {
 		return nil
 	}
-	var elems []branchPageElement
 	data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
-	unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
+	elems := unsafe.Slice((*branchPageElement)(data), int(p.count))
 	return elems
 }
 
diff --git a/vendor/go.etcd.io/bbolt/unsafe.go b/vendor/go.etcd.io/bbolt/unsafe.go
index c0e50375007..7745d32ce19 100644
--- a/vendor/go.etcd.io/bbolt/unsafe.go
+++ b/vendor/go.etcd.io/bbolt/unsafe.go
@@ -1,7 +1,6 @@
 package bbolt
 
 import (
-	"reflect"
 	"unsafe"
 )
 
@@ -26,14 +25,3 @@ func unsafeByteSlice(base unsafe.Pointer, offset uintptr, i, j int) []byte {
 	// all), so this is believed to be correct.
 	return (*[maxAllocSize]byte)(unsafeAdd(base, offset))[i:j:j]
 }
-
-// unsafeSlice modifies the data, len, and cap of a slice variable pointed to by
-// the slice parameter.  This helper should be used over other direct
-// manipulation of reflect.SliceHeader to prevent misuse, namely, converting
-// from reflect.SliceHeader to a Go slice type.
-func unsafeSlice(slice, data unsafe.Pointer, len int) {
-	s := (*reflect.SliceHeader)(slice)
-	s.Data = uintptr(data)
-	s.Cap = len
-	s.Len = len
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 340f0510b07..ed1a2f8910d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1646,7 +1646,7 @@ github.com/prometheus/alertmanager/asset
 github.com/prometheus/alertmanager/pkg/labels
 github.com/prometheus/alertmanager/template
 github.com/prometheus/alertmanager/types
-# github.com/prometheus/client_golang v1.19.0
+# github.com/prometheus/client_golang v1.19.1
 ## explicit; go 1.20
 github.com/prometheus/client_golang/prometheus
 github.com/prometheus/client_golang/prometheus/internal
@@ -1909,8 +1909,8 @@ go-micro.dev/v4/util/ring
 go-micro.dev/v4/util/signal
 go-micro.dev/v4/util/socket
 go-micro.dev/v4/util/tls
-# go.etcd.io/bbolt v1.3.9
-## explicit; go 1.17
+# go.etcd.io/bbolt v1.3.10
+## explicit; go 1.21
 go.etcd.io/bbolt
 # go.etcd.io/etcd/api/v3 v3.5.12
 ## explicit; go 1.20


Test patch:
diff --git a/services/graph/pkg/identity/ldap_education_class_test.go b/services/graph/pkg/identity/ldap_education_class_test.go
index 2b9cc199a2d..1d5bf77e9f2 100644
--- a/services/graph/pkg/identity/ldap_education_class_test.go
+++ b/services/graph/pkg/identity/ldap_education_class_test.go
@@ -273,7 +273,7 @@ func TestGetEducationClassMembers(t *testing.T) {
 			Scope:      0,
 			SizeLimit:  1,
 			Filter:     "(objectClass=inetOrgPerson)",
-			Attributes: []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+			Attributes: ldapUserAttributes,
 			Controls:   []ldap.Control(nil),
 		}
 		lm.On("Search", userSr).Return(&ldap.SearchResult{Entries: []*ldap.Entry{userEntry}}, nil)
diff --git a/services/graph/pkg/identity/ldap_education_user_test.go b/services/graph/pkg/identity/ldap_education_user_test.go
index 3662f8919b8..a84a1df28b6 100644
--- a/services/graph/pkg/identity/ldap_education_user_test.go
+++ b/services/graph/pkg/identity/ldap_education_user_test.go
@@ -194,7 +194,7 @@ func TestUpdateEducationUser(t *testing.T) {
 		Scope:      0,
 		SizeLimit:  1,
 		Filter:     "(objectClass=inetOrgPerson)",
-		Attributes: []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+		Attributes: ldapUserAttributes,
 	}
 	eduUserLookupReq := &ldap.SearchRequest{
 		BaseDN:     "uid=newtestuser,ou=people,dc=test",
diff --git a/services/graph/pkg/identity/ldap_group_test.go b/services/graph/pkg/identity/ldap_group_test.go
index b228a16bb61..a7efaf95581 100644
--- a/services/graph/pkg/identity/ldap_group_test.go
+++ b/services/graph/pkg/identity/ldap_group_test.go
@@ -83,11 +83,11 @@ func TestGetGroup(t *testing.T) {
 		Entries: []*ldap.Entry{invalidGroupEntry},
 	}, nil)
 	b, _ = getMockedBackend(lm, lconfig, &logger)
-	g, err := b.GetGroup(context.Background(), "group", nil)
+	_, err = b.GetGroup(context.Background(), "group", nil)
 	assert.ErrorContains(t, err, "itemNotFound:")
-	g, err = b.GetGroup(context.Background(), "group", queryParamExpand)
+	_, err = b.GetGroup(context.Background(), "group", queryParamExpand)
 	assert.ErrorContains(t, err, "itemNotFound:")
-	g, err = b.GetGroup(context.Background(), "group", queryParamSelect)
+	_, err = b.GetGroup(context.Background(), "group", queryParamSelect)
 	assert.ErrorContains(t, err, "itemNotFound:")
 
 	// Mock a valid	Search Result
@@ -96,14 +96,14 @@ func TestGetGroup(t *testing.T) {
 		BaseDN:     "uid=user,ou=people,dc=test",
 		SizeLimit:  1,
 		Filter:     "(objectClass=inetOrgPerson)",
-		Attributes: []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+		Attributes: ldapUserAttributes,
 		Controls:   []ldap.Control(nil),
 	}
 	sr3 := &ldap.SearchRequest{
 		BaseDN:     "uid=invalid,ou=people,dc=test",
 		SizeLimit:  1,
 		Filter:     "(objectClass=inetOrgPerson)",
-		Attributes: []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+		Attributes: ldapUserAttributes,
 		Controls:   []ldap.Control(nil),
 	}
 
@@ -111,7 +111,7 @@ func TestGetGroup(t *testing.T) {
 	lm.On("Search", sr2).Return(&ldap.SearchResult{Entries: []*ldap.Entry{userEntry}}, nil)
 	lm.On("Search", sr3).Return(&ldap.SearchResult{Entries: []*ldap.Entry{invalidUserEntry}}, nil)
 	b, _ = getMockedBackend(lm, lconfig, &logger)
-	g, err = b.GetGroup(context.Background(), "group", nil)
+	g, err := b.GetGroup(context.Background(), "group", nil)
 	if err != nil {
 		t.Errorf("Expected GetGroup to succeed. Got %s", err.Error())
 	} else if *g.Id != groupEntry.GetEqualFoldAttributeValue(b.groupAttributeMap.id) {
@@ -257,14 +257,14 @@ func TestGetGroups(t *testing.T) {
 		BaseDN:     "uid=user,ou=people,dc=test",
 		SizeLimit:  1,
 		Filter:     "(objectClass=inetOrgPerson)",
-		Attributes: []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+		Attributes: ldapUserAttributes,
 		Controls:   []ldap.Control(nil),
 	}
 	sr3 := &ldap.SearchRequest{
 		BaseDN:     "uid=invalid,ou=people,dc=test",
 		SizeLimit:  1,
 		Filter:     "(objectClass=inetOrgPerson)",
-		Attributes: []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+		Attributes: ldapUserAttributes,
 		Controls:   []ldap.Control(nil),
 	}
 
diff --git a/services/graph/pkg/identity/ldap_test.go b/services/graph/pkg/identity/ldap_test.go
index 71431c674c6..36630cbf759 100644
--- a/services/graph/pkg/identity/ldap_test.go
+++ b/services/graph/pkg/identity/ldap_test.go
@@ -72,6 +72,8 @@ var invalidUserEntry = ldap.NewEntry("uid=user",
 
 var logger = log.NewLogger(log.Level("debug"))
 
+var ldapUserAttributes = []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute", "oCExternalIdentity"}
+
 func TestNewLDAPBackend(t *testing.T) {
 	l := &mocks.Client{}
 
@@ -364,7 +366,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -408,7 +410,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -452,7 +454,7 @@ func TestUpdateUser(t *testing.T) {
 							TimeLimit:    0,
 							TypesOnly:    false,
 							Filter:       "(objectClass=inetOrgPerson)",
-							Attributes:   []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							Attributes:   ldapUserAttributes,
 							Controls:     []ldap.Control(nil),
 						},
 					},
@@ -537,7 +539,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -581,7 +583,7 @@ func TestUpdateUser(t *testing.T) {
 							TimeLimit:    0,
 							TypesOnly:    false,
 							Filter:       "(objectClass=inetOrgPerson)",
-							Attributes:   []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							Attributes:   ldapUserAttributes,
 							Controls:     []ldap.Control(nil),
 						},
 					},
@@ -666,7 +668,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -762,7 +764,7 @@ func TestUpdateUser(t *testing.T) {
 							TimeLimit:    0,
 							TypesOnly:    false,
 							Filter:       "(objectClass=inetOrgPerson)",
-							Attributes:   []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							Attributes:   ldapUserAttributes,
 							Controls:     []ldap.Control(nil),
 						},
 					},
@@ -855,7 +857,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -899,7 +901,7 @@ func TestUpdateUser(t *testing.T) {
 							TimeLimit:    0,
 							TypesOnly:    false,
 							Filter:       "(objectClass=inetOrgPerson)",
-							Attributes:   []string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							Attributes:   ldapUserAttributes,
 							Controls:     []ldap.Control(nil),
 						},
 					},
@@ -985,7 +987,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -1088,7 +1090,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeBaseObject,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(objectClass=inetOrgPerson)",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							[]ldap.Control(nil),
 						),
 					},
@@ -1151,7 +1153,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -1254,7 +1256,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeBaseObject,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(objectClass=inetOrgPerson)",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							[]ldap.Control(nil),
 						),
 					},
@@ -1317,7 +1319,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeWholeSubtree,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(&(objectClass=inetOrgPerson)(|(uid=testUser)(entryUUID=testUser)))",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							nil,
 						),
 					},
@@ -1388,7 +1390,7 @@ func TestUpdateUser(t *testing.T) {
 							ldap.ScopeBaseObject,
 							ldap.NeverDerefAliases, 1, 0, false,
 							"(objectClass=inetOrgPerson)",
-							[]string{"displayname", "entryUUID", "mail", "uid", "sn", "givenname", "userEnabledAttribute", "userTypeAttribute"},
+							ldapUserAttributes,
 							[]ldap.Control(nil),
 						),
 					},
diff --git a/services/settings/pkg/store/filesystem/assignments_test.go b/services/settings/pkg/store/filesystem/assignments_test.go
deleted file mode 100644
index 4f657badc7d..00000000000
--- a/services/settings/pkg/store/filesystem/assignments_test.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package store
-
-import (
-	"errors"
-	"log"
-	"os"
-	"path/filepath"
-	"testing"
-
-	olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-	"github.com/stretchr/testify/assert"
-)
-
-var (
-	einstein = "a4d07560-a670-4be9-8d60-9b547751a208"
-	//marie    = "3c054db3-eec1-4ca4-b985-bc56dcf560cb"
-
-	s = Store{
-		dataPath: dataRoot,
-		Logger:   logger,
-	}
-
-	logger = olog.NewLogger(
-		olog.Color(true),
-		olog.Pretty(true),
-		olog.Level("info"),
-	)
-
-	bundles = []*settingsmsg.Bundle{
-		{
-			Id:          "f36db5e6-a03c-40df-8413-711c67e40b47",
-			Type:        settingsmsg.Bundle_TYPE_ROLE,
-			DisplayName: "test role - reads | update",
-			Name:        "TEST_ROLE",
-			Extension:   "ocis-settings",
-			Resource: &settingsmsg.Resource{
-				Type: settingsmsg.Resource_TYPE_BUNDLE,
-			},
-			Settings: []*settingsmsg.Setting{
-				{
-					Name: "update",
-					Value: &settingsmsg.Setting_PermissionValue{
-						PermissionValue: &settingsmsg.Permission{
-							Operation: settingsmsg.Permission_OPERATION_UPDATE,
-						},
-					},
-				},
-				{
-					Name: "read",
-					Value: &settingsmsg.Setting_PermissionValue{
-						PermissionValue: &settingsmsg.Permission{
-							Operation: settingsmsg.Permission_OPERATION_READ,
-						},
-					},
-				},
-			},
-		},
-		{
-			Id:          "44f1a664-0a7f-461a-b0be-5b59e46bbc7a",
-			Type:        settingsmsg.Bundle_TYPE_ROLE,
-			DisplayName: "another",
-			Name:        "ANOTHER_TEST_ROLE",
-			Extension:   "ocis-settings",
-			Resource: &settingsmsg.Resource{
-				Type: settingsmsg.Resource_TYPE_BUNDLE,
-			},
-			Settings: []*settingsmsg.Setting{
-				{
-					Name: "read",
-					Value: &settingsmsg.Setting_PermissionValue{
-						PermissionValue: &settingsmsg.Permission{
-							Operation: settingsmsg.Permission_OPERATION_READ,
-						},
-					},
-				},
-			},
-		},
-	}
-)
-
-func init() {
-	setupRoles()
-}
-
-func setupRoles() {
-	for i := range bundles {
-		if _, err := s.WriteBundle(bundles[i]); err != nil {
-			log.Fatal(err)
-		}
-	}
-}
-
-func TestAssignmentUniqueness(t *testing.T) {
-	var scenarios = []struct {
-		name       string
-		userID     string
-		firstRole  string
-		secondRole string
-	}{
-		{
-			"roles assignments",
-			einstein,
-			"f36db5e6-a03c-40df-8413-711c67e40b47",
-			"44f1a664-0a7f-461a-b0be-5b59e46bbc7a",
-		},
-	}
-
-	for _, scenario := range scenarios {
-		scenario := scenario
-		t.Run(scenario.name, func(t *testing.T) {
-			firstAssignment, err := s.WriteRoleAssignment(scenario.userID, scenario.firstRole)
-			assert.NoError(t, err)
-			assert.Equal(t, firstAssignment.RoleId, scenario.firstRole)
-			assert.FileExists(t, filepath.Join(dataRoot, "assignments", firstAssignment.Id+".json"))
-
-			list, err := s.ListRoleAssignments(scenario.userID)
-			assert.NoError(t, err)
-			assert.Equal(t, 1, len(list))
-
-			// creating another assignment shouldn't add another entry, as we support max one role per user.
-			secondAssignment, err := s.WriteRoleAssignment(scenario.userID, scenario.secondRole)
-			assert.NoError(t, err)
-			assert.Equal(t, 1, len(list))
-
-			// assigning the second role should remove the old file and create a new one.
-			list, err = s.ListRoleAssignments(scenario.userID)
-			assert.NoError(t, err)
-			assert.Equal(t, 1, len(list))
-			assert.Equal(t, secondAssignment.RoleId, scenario.secondRole)
-			assert.NoFileExists(t, filepath.Join(dataRoot, "assignments", firstAssignment.Id+".json"))
-			assert.FileExists(t, filepath.Join(dataRoot, "assignments", secondAssignment.Id+".json"))
-		})
-	}
-	burnRoot()
-}
-
-func TestDeleteAssignment(t *testing.T) {
-	var scenarios = []struct {
-		name       string
-		userID     string
-		firstRole  string
-		secondRole string
-	}{
-		{
-			"roles assignments",
-			einstein,
-			"f36db5e6-a03c-40df-8413-711c67e40b47",
-			"44f1a664-0a7f-461a-b0be-5b59e46bbc7a",
-		},
-	}
-
-	for _, scenario := range scenarios {
-		scenario := scenario
-		t.Run(scenario.name, func(t *testing.T) {
-			assignment, err := s.WriteRoleAssignment(scenario.userID, scenario.firstRole)
-			assert.NoError(t, err)
-			assert.Equal(t, assignment.RoleId, scenario.firstRole)
-			assert.FileExists(t, filepath.Join(dataRoot, "assignments", assignment.Id+".json"))
-
-			list, err := s.ListRoleAssignments(scenario.userID)
-			assert.NoError(t, err)
-			assert.Equal(t, 1, len(list))
-
-			err = s.RemoveRoleAssignment(assignment.Id)
-			assert.NoError(t, err)
-
-			list, err = s.ListRoleAssignments(scenario.userID)
-			assert.NoError(t, err)
-			assert.Equal(t, 0, len(list))
-
-			err = s.RemoveRoleAssignment(assignment.Id)
-			merr := &os.PathError{}
-			assert.Equal(t, true, errors.As(err, &merr))
-		})
-	}
-	burnRoot()
-}
diff --git a/services/settings/pkg/store/filesystem/bundles_test.go b/services/settings/pkg/store/filesystem/bundles_test.go
deleted file mode 100644
index c7695bca625..00000000000
--- a/services/settings/pkg/store/filesystem/bundles_test.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package store
-
-import (
-	"testing"
-
-	olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-	"github.com/stretchr/testify/assert"
-)
-
-var bundleScenarios = []struct {
-	name   string
-	bundle *settingsmsg.Bundle
-}{
-	{
-		name: "generic-test-file-resource",
-		bundle: &settingsmsg.Bundle{
-			Id:          bundle1,
-			Type:        settingsmsg.Bundle_TYPE_DEFAULT,
-			Extension:   extension1,
-			DisplayName: "test1",
-			Resource: &settingsmsg.Resource{
-				Type: settingsmsg.Resource_TYPE_FILE,
-				Id:   "beep",
-			},
-			Settings: []*settingsmsg.Setting{
-				{
-					Id:          setting1,
-					Description: "test-desc-1",
-					DisplayName: "test-displayname-1",
-					Resource: &settingsmsg.Resource{
-						Type: settingsmsg.Resource_TYPE_FILE,
-						Id:   "bleep",
-					},
-					Value: &settingsmsg.Setting_IntValue{
-						IntValue: &settingsmsg.Int{
-							Min: 0,
-							Max: 42,
-						},
-					},
-				},
-			},
-		},
-	},
-	{
-		name: "generic-test-system-resource",
-		bundle: &settingsmsg.Bundle{
-			Id:          bundle2,
-			Type:        settingsmsg.Bundle_TYPE_DEFAULT,
-			Extension:   extension2,
-			DisplayName: "test1",
-			Resource: &settingsmsg.Resource{
-				Type: settingsmsg.Resource_TYPE_SYSTEM,
-			},
-			Settings: []*settingsmsg.Setting{
-				{
-					Id:          setting2,
-					Description: "test-desc-2",
-					DisplayName: "test-displayname-2",
-					Resource: &settingsmsg.Resource{
-						Type: settingsmsg.Resource_TYPE_SYSTEM,
-					},
-					Value: &settingsmsg.Setting_IntValue{
-						IntValue: &settingsmsg.Int{
-							Min: 0,
-							Max: 42,
-						},
-					},
-				},
-			},
-		},
-	},
-	{
-		name: "generic-test-role-bundle",
-		bundle: &settingsmsg.Bundle{
-			Id:          bundle3,
-			Type:        settingsmsg.Bundle_TYPE_ROLE,
-			Extension:   extension1,
-			DisplayName: "Role1",
-			Resource: &settingsmsg.Resource{
-				Type: settingsmsg.Resource_TYPE_SYSTEM,
-			},
-			Settings: []*settingsmsg.Setting{
-				{
-					Id:          setting3,
-					Description: "test-desc-3",
-					DisplayName: "test-displayname-3",
-					Resource: &settingsmsg.Resource{
-						Type: settingsmsg.Resource_TYPE_SETTING,
-						Id:   setting1,
-					},
-					Value: &settingsmsg.Setting_PermissionValue{
-						PermissionValue: &settingsmsg.Permission{
-							Operation:  settingsmsg.Permission_OPERATION_READ,
-							Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
-						},
-					},
-				},
-			},
-		},
-	},
-}
-
-func TestBundles(t *testing.T) {
-	s := Store{
-		dataPath: dataRoot,
-		Logger: olog.NewLogger(
-			olog.Color(true),
-			olog.Pretty(true),
-			olog.Level("info"),
-		),
-	}
-
-	// write bundles
-	for i := range bundleScenarios {
-		index := i
-		t.Run(bundleScenarios[index].name, func(t *testing.T) {
-			filePath := s.buildFilePathForBundle(bundleScenarios[index].bundle.Id, true)
-			if err := s.writeRecordToFile(bundleScenarios[index].bundle, filePath); err != nil {
-				t.Error(err)
-			}
-			assert.FileExists(t, filePath)
-		})
-	}
-
-	// check that ListBundles only returns bundles with type DEFAULT
-	bundles, err := s.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, []string{})
-	if err != nil {
-		t.Error(err)
-	}
-	for i := range bundles {
-		assert.Equal(t, settingsmsg.Bundle_TYPE_DEFAULT, bundles[i].Type)
-	}
-
-	// check that ListBundles filtered by an id only returns that bundle
-	filteredBundles, err := s.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, []string{bundle2})
-	if err != nil {
-		t.Error(err)
-	}
-	assert.Equal(t, 1, len(filteredBundles))
-	if len(filteredBundles) == 1 {
-		assert.Equal(t, bundle2, filteredBundles[0].Id)
-	}
-
-	// check that ListRoles only returns bundles with type ROLE
-	roles, err := s.ListBundles(settingsmsg.Bundle_TYPE_ROLE, []string{})
-	if err != nil {
-		t.Error(err)
-	}
-	for i := range roles {
-		assert.Equal(t, settingsmsg.Bundle_TYPE_ROLE, roles[i].Type)
-	}
-
-	burnRoot()
-}
diff --git a/services/settings/pkg/store/filesystem/store_test.go b/services/settings/pkg/store/filesystem/store_test.go
deleted file mode 100644
index 26f22d1ae75..00000000000
--- a/services/settings/pkg/store/filesystem/store_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package store
-
-import (
-	"os"
-	"path/filepath"
-)
-
-const (
-	// account UUIDs
-	accountUUID1 = "c4572da7-6142-4383-8fc6-efde3d463036"
-	//accountUUID2 = "e11f9769-416a-427d-9441-41a0e51391d7"
-	//accountUUID3 = "633ecd77-1980-412a-8721-bf598a330bb4"
-
-	// extension names
-	extension1 = "test-extension-1"
-	extension2 = "test-extension-2"
-
-	// bundle ids
-	bundle1 = "2f06addf-4fd2-49d5-8f71-00fbd3a3ec47"
-	bundle2 = "2d745744-749c-4286-8e92-74a24d8331c5"
-	bundle3 = "d8fd27d1-c00b-4794-a658-416b756a72ff"
-
-	// setting ids
-	setting1 = "c7ebbc8b-d15a-4f2e-9d7d-d6a4cf858d1a"
-	setting2 = "3fd9a3d9-20b7-40d4-9294-b22bb5868c10"
-	setting3 = "24bb9535-3df4-42f1-a622-7c0562bec99f"
-
-	// value ids
-	value1 = "fd3b6221-dc13-4a22-824d-2480495f1cdb"
-	value2 = "2a0bd9b0-ca1d-491a-8c56-d2ddfd68ded8"
-	//value3 = "b42702d2-5e4d-4d73-b133-e1f9e285355e"
-
-	dataRoot = "/tmp/herecomesthesun"
-)
-
-func burnRoot() {
-	os.RemoveAll(filepath.Join(dataRoot, "values"))
-	os.RemoveAll(filepath.Join(dataRoot, "bundles"))
-}
diff --git a/services/settings/pkg/store/filesystem/values_test.go b/services/settings/pkg/store/filesystem/values_test.go
deleted file mode 100644
index 765947dc177..00000000000
--- a/services/settings/pkg/store/filesystem/values_test.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package store
-
-import (
-	"testing"
-
-	olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
-	settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
-	"github.com/stretchr/testify/assert"
-)
-
-var valueScenarios = []struct {
-	name  string
-	value *settingsmsg.Value
-}{
-	{
-		name: "generic-test-with-system-resource",
-		value: &settingsmsg.Value{
-			Id:          value1,
-			BundleId:    bundle1,
-			SettingId:   setting1,
-			AccountUuid: accountUUID1,
-			Resource: &settingsmsg.Resource{
-				Type: settingsmsg.Resource_TYPE_SYSTEM,
-			},
-			Value: &settingsmsg.Value_StringValue{
-				StringValue: "lalala",
-			},
-		},
-	},
-	{
-		name: "generic-test-with-file-resource",
-		value: &settingsmsg.Value{
-			Id:          value2,
-			BundleId:    bundle1,
-			SettingId:   setting2,
-			AccountUuid: accountUUID1,
-			Resource: &settingsmsg.Resource{
-				Type: settingsmsg.Resource_TYPE_FILE,
-				Id:   "adfba82d-919a-41c3-9cd1-5a3f83b2bf76",
-			},
-			Value: &settingsmsg.Value_StringValue{
-				StringValue: "tralala",
-			},
-		},
-	},
-}
-
-func TestValues(t *testing.T) {
-	s := Store{
-		dataPath: dataRoot,
-		Logger: olog.NewLogger(
-			olog.Color(true),
-			olog.Pretty(true),
-			olog.Level("info"),
-		),
-	}
-	for i := range valueScenarios {
-		index := i
-		t.Run(valueScenarios[index].name, func(t *testing.T) {
-
-			filePath := s.buildFilePathForValue(valueScenarios[index].value.Id, true)
-			if err := s.writeRecordToFile(valueScenarios[index].value, filePath); err != nil {
-				t.Error(err)
-			}
-			assert.FileExists(t, filePath)
-		})
-	}
-
-	burnRoot()
-}
diff --git a/tests/acceptance/config/behat-core.yml b/tests/acceptance/config/behat-core.yml
index b0071b5466e..f4f6a1d076e 100644
--- a/tests/acceptance/config/behat-core.yml
+++ b/tests/acceptance/config/behat-core.yml
@@ -50,6 +50,7 @@ default:
         - FeatureContext: *common_feature_context_params
         - FavoritesContext:
         - WebDavPropertiesContext:
+        - SharingNgContext:
 
     coreApiShareCreateSpecialToShares1:
       paths:
diff --git a/tests/acceptance/docker/src/ocis-base.yml b/tests/acceptance/docker/src/ocis-base.yml
index 0407639b4d3..4da6b626bea 100644
--- a/tests/acceptance/docker/src/ocis-base.yml
+++ b/tests/acceptance/docker/src/ocis-base.yml
@@ -14,7 +14,6 @@ services:
       STORAGE_USERS_DRIVER_OCIS_ROOT: /srv/app/tmp/ocis/storage/users
       STORAGE_SYSTEM_DRIVER_OCIS_ROOT: /srv/app/tmp/ocis/storage/metadata
       SHARING_USER_JSON_FILE: /srv/app/tmp/ocis/shares.json
-      SETTINGS_DATA_PATH: "/srv/app/tmp/ocis/settings"
       PROXY_ENABLE_BASIC_AUTH: "true"
       WEB_UI_CONFIG_FILE: /drone/src/tests/config/drone/ocis-config.json
       ACCOUNTS_HASH_DIFFICULTY: 4
diff --git a/tests/acceptance/expected-failures-API-on-OCIS-storage.md b/tests/acceptance/expected-failures-API-on-OCIS-storage.md
index 3306a9fa4fb..541a1451eaa 100644
--- a/tests/acceptance/expected-failures-API-on-OCIS-storage.md
+++ b/tests/acceptance/expected-failures-API-on-OCIS-storage.md
@@ -238,8 +238,8 @@ And other missing implementation of favorites
 - [coreApiFavorites/favorites.feature:202](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiFavorites/favorites.feature#L202)
 - [coreApiFavorites/favorites.feature:203](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiFavorites/favorites.feature#L203)
 - [coreApiFavorites/favorites.feature:208](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiFavorites/favorites.feature#L208)
-- [coreApiFavorites/favoritesSharingToShares.feature:64](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature#L64)
-- [coreApiFavorites/favoritesSharingToShares.feature:65](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature#L65)
+- [coreApiFavorites/favoritesSharingToShares.feature:84](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature#L84)
+- [coreApiFavorites/favoritesSharingToShares.feature:85](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature#L85)
 
 #### [WWW-Authenticate header for unauthenticated requests is not clear](https://github.com/owncloud/ocis/issues/2285)
 
diff --git a/tests/acceptance/features/apiSpaces/restoreSpaces.feature b/tests/acceptance/features/apiSpaces/restoreSpaces.feature
index 6878fc01b72..6626964d119 100644
--- a/tests/acceptance/features/apiSpaces/restoreSpaces.feature
+++ b/tests/acceptance/features/apiSpaces/restoreSpaces.feature
@@ -26,12 +26,16 @@ Feature: Restoring space
   Scenario: participants can see the data after the space is restored
     Given user "Alice" has created a folder "mainFolder" in space "restore a space"
     And user "Alice" has uploaded a file inside space "restore a space" with content "example" to "test.txt"
-    And user "Alice" has shared a space "restore a space" with settings:
-      | shareWith | Brian  |
-      | role      | editor |
-    And user "Alice" has shared a space "restore a space" with settings:
-      | shareWith | Bob    |
-      | role      | viewer |
+    And user "Alice" has sent the following space share invitation:
+      | space           | restore a space |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | Space Editor    |
+    And user "Alice" has sent the following space share invitation:
+      | space           | restore a space |
+      | sharee          | Bob             |
+      | shareType       | user            |
+      | permissionsRole | Space Viewer    |
     And user "Alice" has disabled a space "restore a space"
     When user "Alice" restores a disabled space "restore a space"
     Then for user "Alice" the space "restore a space" should contain these entries:
@@ -46,9 +50,11 @@ Feature: Restoring space
 
 
   Scenario: participant can create data in the space after restoring
-    Given user "Alice" has shared a space "restore a space" with settings:
-      | shareWith | Brian  |
-      | role      | editor |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | restore a space |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | Space Editor    |
     And user "Alice" has disabled a space "restore a space"
     And user "Alice" has restored a disabled space "restore a space"
     When user "Brian" creates a folder "mainFolder" in space "restore a space" using the WebDav Api
@@ -59,16 +65,18 @@ Feature: Restoring space
 
 
   Scenario Outline: user without space manager role cannot restore space
-    Given user "Alice" has shared a space "restore a space" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | restore a space |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | <space-role>    |
     And user "Alice" has disabled a space "restore a space"
     When user "Brian" tries to restore a disabled space "restore a space" owned by user "Alice"
     Then the HTTP status code should be "404"
     Examples:
-      | space-role |
-      | viewer     |
-      | editor     |
+      | space-role   |
+      | Space Viewer |
+      | Space Editor |
 
 
   Scenario Outline: user with role user and user light cannot restore space
diff --git a/tests/acceptance/features/apiSpaces/setQuota.feature b/tests/acceptance/features/apiSpaces/setQuota.feature
index 760b1be3d7f..34d22d845b3 100644
--- a/tests/acceptance/features/apiSpaces/setQuota.feature
+++ b/tests/acceptance/features/apiSpaces/setQuota.feature
@@ -111,19 +111,21 @@ Feature: Set quota
     Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
     And the administrator has assigned the role "<user-role>" to user "Brian" using the Graph API
     And user "Alice" has created a space "Project Jupiter" of type "project" with quota "20"
-    And user "Alice" has shared a space "Project Jupiter" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    And user "Alice" has sent the following space share invitation:
+      | space           | Project Jupiter |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | <space-role>    |
     When user "Brian" changes the quota of the "Project Jupiter" space to "100"
     Then the HTTP status code should be "403"
     Examples:
-      | user-role  | space-role |
-      | User       | viewer     |
-      | User       | editor     |
-      | User       | manager    |
-      | User Light | viewer     |
-      | User Light | editor     |
-      | User Light | manager    |
+      | user-role  | space-role   |
+      | User       | Space Viewer |
+      | User       | Space Editor |
+      | User       | Manager      |
+      | User Light | Space Viewer |
+      | User Light | Space Editor |
+      | User Light | Manager      |
 
 
   Scenario: admin user can set their own personal space quota
diff --git a/tests/acceptance/features/apiSpaces/tag.feature b/tests/acceptance/features/apiSpaces/tag.feature
index 8622564fc87..106cdbe8293 100644
--- a/tests/acceptance/features/apiSpaces/tag.feature
+++ b/tests/acceptance/features/apiSpaces/tag.feature
@@ -19,9 +19,11 @@ Feature: Tag
 
 
   Scenario: user creates tags for resources in the project space
-    Given user "Alice" has shared a space "use-tag" with settings:
-      | shareWith | Brian  |
-      | role      | viewer |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | use-tag      |
+      | sharee          | Brian        |
+      | shareType       | user         |
+      | permissionsRole | Space Viewer |
     When user "Alice" creates the following tags for folder "folderMain" of space "use-tag":
       | tag level#1                    |
       | tag with symbols @^$#^%$@%!_+) |
@@ -84,9 +86,11 @@ Feature: Tag
 
 
   Scenario Outline: member of the space tries to create tag
-    Given user "Alice" has shared a space "use-tag" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | use-tag      |
+      | sharee          | Brian        |
+      | shareType       | user         |
+      | permissionsRole | <space-role> |
     When user "Brian" creates the following tags for folder "folderMain/insideTheFolder.txt" of space "use-tag":
       | tag level#1                    |
       | tag with symbols @^$#^%$@%!_+) |
@@ -97,10 +101,10 @@ Feature: Tag
       | tag level#1                    |
       | tag with symbols @^$#^%$@%!_+) |
     Examples:
-      | space-role | http-status-code | should-or-not |
-      | viewer     | 403              | should not    |
-      | editor     | 200              | should        |
-      | manager    | 200              | should        |
+      | space-role   | http-status-code | should-or-not |
+      | Space Viewer | 403              | should not    |
+      | Space Editor | 200              | should        |
+      | Manager      | 200              | should        |
 
 
   Scenario: recipient has a created tags if share is accepted
@@ -245,9 +249,11 @@ Feature: Tag
 
 
   Scenario: user creates a comma-separated list of tags for resources in the project space
-    Given user "Alice" has shared a space "use-tag" with settings:
-      | shareWith | Brian  |
-      | role      | viewer |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | use-tag      |
+      | sharee          | Brian        |
+      | shareType       | user         |
+      | permissionsRole | Space Viewer |
     When user "Alice" creates the following tags for folder "folderMain" of space "use-tag":
       | finance,नेपाल |
     Then the HTTP status code should be "200"
diff --git a/tests/acceptance/features/apiSpaces/trashBin.feature b/tests/acceptance/features/apiSpaces/trashBin.feature
index b0405e86556..61293da2c6c 100644
--- a/tests/acceptance/features/apiSpaces/trashBin.feature
+++ b/tests/acceptance/features/apiSpaces/trashBin.feature
@@ -19,9 +19,11 @@ Feature: Restore files, folder
 
 
   Scenario Outline: user with different role can see deleted objects in trash bin of the space via the webDav API
-    Given user "Alice" has shared a space "restore objects" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | restore objects |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | <space-role>    |
     And user "Alice" has removed the file "newFolder/file.txt" from space "restore objects"
     And user "Alice" has removed the folder "newFolder" from space "restore objects"
     When user "Brian" lists all deleted files in the trash bin of the space "restore objects"
@@ -29,16 +31,18 @@ Feature: Restore files, folder
     And as "Brian" folder "newFolder" should exist in the trashbin of the space "restore objects"
     And as "Brian" file "file.txt" should exist in the trashbin of the space "restore objects"
     Examples:
-      | space-role |
-      | manager    |
-      | editor     |
-      | viewer     |
+      | space-role   |
+      | Manager      |
+      | Space Editor |
+      | Space Viewer |
 
 
   Scenario Outline: user can restore a folder with some objects from the trash via the webDav API
-    Given user "Alice" has shared a space "restore objects" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | restore objects |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | <space-role>    |
     And user "Alice" has removed the folder "newFolder" from space "restore objects"
     When user "<user>" restores the folder "newFolder" from the trash of the space "restore objects" to "/newFolder"
     Then the HTTP status code should be "<http-status-code>"
@@ -46,17 +50,19 @@ Feature: Restore files, folder
       | newFolder |
     And as "<user>" folder "newFolder" <should-or-not-be-in-trash> exist in the trashbin of the space "restore objects"
     Examples:
-      | user  | space-role | http-status-code | should-or-not-be-in-space | should-or-not-be-in-trash |
-      | Alice | manager    | 201              | should                    | should not                |
-      | Brian | manager    | 201              | should                    | should not                |
-      | Brian | editor     | 201              | should                    | should not                |
-      | Brian | viewer     | 403              | should not                | should                    |
+      | user  | space-role   | http-status-code | should-or-not-be-in-space | should-or-not-be-in-trash |
+      | Alice | Manager      | 201              | should                    | should not                |
+      | Brian | Manager      | 201              | should                    | should not                |
+      | Brian | Space Editor | 201              | should                    | should not                |
+      | Brian | Space Viewer | 403              | should not                | should                    |
 
 
   Scenario Outline: user can restore a file from the trash via the webDav API
-    Given user "Alice" has shared a space "restore objects" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | restore objects |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | <space-role>    |
     And user "Alice" has removed the file "newFolder/file.txt" from space "restore objects"
     When user "<user>" restores the file "file.txt" from the trash of the space "restore objects" to "newFolder/file.txt"
     Then the HTTP status code should be "<http-status-code>"
@@ -64,27 +70,29 @@ Feature: Restore files, folder
       | file.txt |
     And as "<user>" file "file.txt" <should-or-not-be-in-trash> exist in the trashbin of the space "restore objects"
     Examples:
-      | user  | space-role | http-status-code | should-or-not-be-in-space | should-or-not-be-in-trash |
-      | Alice | manager    | 201              | should                    | should not                |
-      | Brian | manager    | 201              | should                    | should not                |
-      | Brian | editor     | 201              | should                    | should not                |
-      | Brian | viewer     | 403              | should not                | should                    |
+      | user  | space-role   | http-status-code | should-or-not-be-in-space | should-or-not-be-in-trash |
+      | Alice | Manager      | 201              | should                    | should not                |
+      | Brian | Manager      | 201              | should                    | should not                |
+      | Brian | Space Editor | 201              | should                    | should not                |
+      | Brian | Space Viewer | 403              | should not                | should                    |
 
 
   Scenario Outline: only space manager can purge the trash via the webDav API
-    Given user "Alice" has shared a space "restore objects" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | restore objects |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | <space-role>    |
     And the administrator has assigned the role "Space Admin" to user "Brian" using the Graph API
     And user "Alice" has removed the file "newFolder/file.txt" from space "restore objects"
     When user "Brian" deletes the file "file.txt" from the trash of the space "restore objects"
     Then the HTTP status code should be "<http-status-code>"
     And as "Brian" file "file.txt" <should-or-not-be-in-trash> exist in the trashbin of the space "restore objects"
     Examples:
-      | space-role | http-status-code | should-or-not-be-in-trash |
-      | manager    | 204              | should not                |
-      | editor     | 403              | should                    |
-      | viewer     | 403              | should                    |
+      | space-role   | http-status-code | should-or-not-be-in-trash |
+      | Manager      | 204              | should not                |
+      | Space Editor | 403              | should                    |
+      | Space Viewer | 403              | should                    |
 
 
   Scenario Outline: admin user who is not a member of space cannot see its trash bin
@@ -99,9 +107,11 @@ Feature: Restore files, folder
 
 
   Scenario Outline: admin user without space-manager role cannot purge the trash
-    Given user "Alice" has shared a space "restore objects" with settings:
-      | shareWith | Brian  |
-      | role      | editor |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | restore objects |
+      | sharee          | Brian           |
+      | shareType       | user            |
+      | permissionsRole | Space Editor    |
     And the administrator has assigned the role "<user-role>" to user "Brian" using the Graph API
     And user "Alice" has removed the file "newFolder/file.txt" from space "restore objects"
     When user "Brian" tries to delete the file "file.txt" from the trash of the space "restore objects"
diff --git a/tests/acceptance/features/apiSpaces/tusUpload.feature b/tests/acceptance/features/apiSpaces/tusUpload.feature
index ce0c7bc82e7..21403c530a7 100644
--- a/tests/acceptance/features/apiSpaces/tusUpload.feature
+++ b/tests/acceptance/features/apiSpaces/tusUpload.feature
@@ -45,7 +45,12 @@ Feature: upload resources using TUS protocol
     Given using <dav-path-version> DAV path
     And user "Brian" has been created with default attributes and without skeleton files
     And user "Alice" has created folder "testFolder"
-    And user "Alice" has shared folder "testFolder" with user "Brian" with permissions "all"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | testFolder |
+      | space           | Personal   |
+      | sharee          | Brian      |
+      | shareType       | user       |
+      | permissionsRole | Editor     |
     When user "Brian" uploads file "filesForUpload/zerobyte.txt" to "Shares/testFolder/textfile.txt" using the TUS protocol on the WebDAV API
     Then the content of file "Shares/testFolder/textfile.txt" for user "Brian" should be ""
     And the content of file "testFolder/textfile.txt" for user "Alice" should be ""
@@ -59,7 +64,12 @@ Feature: upload resources using TUS protocol
     Given using spaces DAV path
     And user "Brian" has been created with default attributes and without skeleton files
     And user "Alice" has created folder "testFolder"
-    And user "Alice" has shared folder "testFolder" with user "Brian" with permissions "all"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | testFolder |
+      | space           | Personal   |
+      | sharee          | Brian      |
+      | shareType       | user       |
+      | permissionsRole | Editor     |
     When user "Brian" uploads a file from "filesForUpload/zerobyte.txt" to "testFolder/textfile.txt" via TUS inside of the space "Shares" using the WebDAV API
     Then for user "Brian" the content of the file "testFolder/textfile.txt" of the space "Shares" should be ""
     And for user "Alice" the content of the file "testFolder/textfile.txt" of the space "Personal" should be ""
@@ -77,7 +87,12 @@ Feature: upload resources using TUS protocol
     Given using <dav-path-version> DAV path
     And user "Brian" has been created with default attributes and without skeleton files
     And user "Alice" has uploaded file with content "This is TUS upload" to "textfile.txt"
-    And user "Alice" has shared file "textfile.txt" with user "Brian" with permissions "read,update"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | textfile.txt |
+      | space           | Personal     |
+      | sharee          | Brian        |
+      | shareType       | user         |
+      | permissionsRole | File Editor  |
     When user "Brian" uploads file "filesForUpload/zerobyte.txt" to "Shares/textfile.txt" using the TUS protocol on the WebDAV API
     Then the content of file "Shares/textfile.txt" for user "Brian" should be ""
     And the content of file "textfile.txt" for user "Alice" should be ""
@@ -91,7 +106,12 @@ Feature: upload resources using TUS protocol
     Given using spaces DAV path
     And user "Brian" has been created with default attributes and without skeleton files
     And user "Alice" has uploaded file with content "This is TUS upload" to "textfile.txt"
-    And user "Alice" has shared file "textfile.txt" with user "Brian" with permissions "read,update"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | textfile.txt |
+      | space           | Personal     |
+      | sharee          | Brian        |
+      | shareType       | user         |
+      | permissionsRole | File Editor  |
     When user "Brian" uploads a file from "filesForUpload/zerobyte.txt" to "textfile.txt" via TUS inside of the space "Shares" using the WebDAV API
     Then for user "Brian" the content of the file "textfile.txt" of the space "Shares" should be ""
     And for user "Alice" the content of the file "textfile.txt" of the space "Personal" should be ""
@@ -112,9 +132,11 @@ Feature: upload resources using TUS protocol
     And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
     And user "Alice" has created a space "new-space" with the default quota using the Graph API
     And user "Alice" has uploaded a file inside space "new-space" with content "This is TUS upload" to "textfile.txt"
-    And user "Alice" has shared a space "new-space" with settings:
-      | shareWith | Brian  |
-      | role      | editor |
+    And user "Alice" has sent the following space share invitation:
+      | space           | new-space    |
+      | sharee          | Brian        |
+      | shareType       | user         |
+      | permissionsRole | Space Editor |
     When user "Brian" uploads a file from "filesForUpload/zerobyte.txt" to "textfile.txt" via TUS inside of the space "new-space" using the WebDAV API
     Then for user "Brian" the content of the file "textfile.txt" of the space "new-space" should be ""
-    And for user "Alice" the content of the file "textfile.txt" of the space "new-space" should be ""
\ No newline at end of file
+    And for user "Alice" the content of the file "textfile.txt" of the space "new-space" should be ""
diff --git a/tests/acceptance/features/apiSpaces/uploadSpaces.feature b/tests/acceptance/features/apiSpaces/uploadSpaces.feature
index bf2ca4f6026..a6e343c2844 100644
--- a/tests/acceptance/features/apiSpaces/uploadSpaces.feature
+++ b/tests/acceptance/features/apiSpaces/uploadSpaces.feature
@@ -18,33 +18,37 @@ Feature: Upload files into a space
 
 
   Scenario Outline: user creates a folder in the space via the Graph API
-    Given user "Alice" has shared a space "Project Ceres" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | Project Ceres |
+      | sharee          | Brian         |
+      | shareType       | user          |
+      | permissionsRole | <space-role>  |
     When user "Brian" creates a folder "mainFolder" in space "Project Ceres" using the WebDav Api
     Then the HTTP status code should be "<http-status-code>"
     And for user "Brian" the space "Project Ceres" <should-or-not> contain these entries:
       | mainFolder |
     Examples:
-      | space-role | http-status-code | should-or-not |
-      | manager    | 201              | should        |
-      | editor     | 201              | should        |
-      | viewer     | 403              | should not    |
+      | space-role   | http-status-code | should-or-not |
+      | Manager      | 201              | should        |
+      | Space Editor | 201              | should        |
+      | Space Viewer | 403              | should not    |
 
 
   Scenario Outline: user uploads a file in shared space via the Graph API
-    Given user "Alice" has shared a space "Project Ceres" with settings:
-      | shareWith | Brian        |
-      | role      | <space-role> |
+    Given user "Alice" has sent the following space share invitation:
+      | space           | Project Ceres |
+      | sharee          | Brian         |
+      | shareType       | user          |
+      | permissionsRole | <space-role>  |
     When user "Brian" uploads a file inside space "Project Ceres" with content "Test" to "test.txt" using the WebDAV API
     Then the HTTP status code should be "<http-status-code>"
     And for user "Brian" the space "Project Ceres" <should-or-not> contain these entries:
       | test.txt |
     Examples:
-      | space-role | http-status-code | should-or-not |
-      | manager    | 201              | should        |
-      | editor     | 201              | should        |
-      | viewer     | 403              | should not    |
+      | space-role   | http-status-code | should-or-not |
+      | Manager      | 201              | should        |
+      | Space Editor | 201              | should        |
+      | Space Viewer | 403              | should not    |
 
 
   Scenario: user can create subfolders in a space via the Graph API
diff --git a/tests/acceptance/features/bootstrap/ChecksumContext.php b/tests/acceptance/features/bootstrap/ChecksumContext.php
index 8363813a737..636898e855f 100644
--- a/tests/acceptance/features/bootstrap/ChecksumContext.php
+++ b/tests/acceptance/features/bootstrap/ChecksumContext.php
@@ -127,25 +127,6 @@ class ChecksumContext implements Context {
 		);
 	}
 
-	/**
-	 * @When user :user uploads file with content :content and checksum :checksum to :destination using the WebDAV API
-	 *
-	 * @param string $user
-	 * @param string $content
-	 * @param string $checksum
-	 * @param string $destination
-	 *
-	 * @return void
-	 */
-	public function userUploadsFileWithContentAndChecksumToUsingTheAPI(
-		string $user,
-		string $content,
-		string $checksum,
-		string $destination
-	):void {
-		$this->featureContext->setResponse($this->uploadFileWithContentAndChecksumToUsingTheAPI($user, $content, $checksum, $destination));
-	}
-
 	/**
 	 * @Given user :user has uploaded file with content :content and checksum :checksum to :destination
 	 *
@@ -176,6 +157,16 @@ class ChecksumContext implements Context {
 	 * @return void
 	 */
 	public function userRequestsTheChecksumOfViaPropfind(string $user, string $path):void {
+		$this->featureContext->setResponse($this->propfindResourceChecksum($user, $path));
+	}
+
+	/**
+	 * @param string $user
+	 * @param string $path
+	 *
+	 * @return ResponseInterface
+	 */
+	public function propfindResourceChecksum(string $user, string $path) : ResponseInterface {
 		$user = $this->featureContext->getActualUsername($user);
 		$body = '<?xml version="1.0"?>
 			<d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
@@ -184,7 +175,7 @@ class ChecksumContext implements Context {
 			  </d:prop>
 			</d:propfind>';
 		$password = $this->featureContext->getPasswordForUser($user);
-		$response = WebDavHelper::makeDavRequest(
+		return WebDavHelper::makeDavRequest(
 			$this->featureContext->getBaseUrl(),
 			$user,
 			$password,
@@ -195,7 +186,6 @@ class ChecksumContext implements Context {
 			$body,
 			$this->featureContext->getDavPathVersion()
 		);
-		$this->featureContext->setResponse($response);
 	}
 
 	/**
@@ -207,8 +197,34 @@ class ChecksumContext implements Context {
 	 * @throws Exception
 	 */
 	public function theWebdavChecksumShouldMatch(string $expectedChecksum):void {
-		$service = new Sabre\Xml\Service();
 		$bodyContents = $this->featureContext->getResponse()->getBody()->getContents();
+		$this->validateChecksum($bodyContents, $expectedChecksum);
+	}
+
+	/**
+	 * @Then as user :user the webdav checksum of :path via propfind should match :expectedChecksum
+	 *
+	 * @param string $user
+	 * @param string $path
+	 * @param string $expectedChecksum
+	 *
+	 * @return void
+	 * @throws Exception
+	 */
+	public function asUserTheWebdavChecksumOfPathViaPropfindShouldMatch(string $user, string $path, string $expectedChecksum):void {
+		$user = $this->featureContext->getActualUsername($user);
+		$resource = $this->propfindResourceChecksum($user, $path);
+		$bodyContents = $resource->getBody()->getContents();
+		$this->validateChecksum($bodyContents, $expectedChecksum);
+	}
+	/**
+	 * @param string $bodyContents
+	 * @param string $expectedChecksum
+	 *
+	 * @return void
+	 */
+	public function validateChecksum(string $bodyContents, string $expectedChecksum):void {
+		$service = new Sabre\Xml\Service();
 		$parsed = $service->parse($bodyContents);
 
 		/*
@@ -293,22 +309,6 @@ class ChecksumContext implements Context {
 		);
 	}
 
-	/**
-	 * @Then as user :user the webdav checksum of :path via propfind should match :expectedChecksum
-	 *
-	 * @param string $user
-	 * @param string $path
-	 * @param string $expectedChecksum
-	 *
-	 * @return void
-	 * @throws Exception
-	 */
-	public function theWebdavChecksumOfViaPropfindShouldMatch(string $user, string $path, string $expectedChecksum):void {
-		$user = $this->featureContext->getActualUsername($user);
-		$this->userRequestsTheChecksumOfViaPropfind($user, $path);
-		$this->theWebdavChecksumShouldMatch($expectedChecksum);
-	}
-
 	/**
 	 * @Then the header checksum should match :expectedChecksum
 	 *
@@ -359,46 +359,31 @@ class ChecksumContext implements Context {
 	 */
 	public function theHeaderChecksumWhenUserDownloadsFileUsingTheWebdavApiShouldMatch(string $user, string $fileName, string $expectedChecksum):void {
 		$this->featureContext->userDownloadsFileUsingTheAPI($user, $fileName);
-		$this->theHeaderChecksumShouldMatch($expectedChecksum);
-	}
+		$headerChecksums = $this->featureContext->getResponse()->getHeader('OC-Checksum');
 
-	/**
-	 * @Then the webdav checksum should be empty
-	 *
-	 * @return void
-	 * @throws Exception
-	 */
-	public function theWebdavChecksumShouldBeEmpty():void {
-		$service = new Sabre\Xml\Service();
-		$parsed = $service->parse(
-			$this->featureContext->getResponse()->getBody()->getContents()
+		Assert::assertIsArray(
+			$headerChecksums,
+			__METHOD__ . " getHeader('OC-Checksum') did not return an array"
 		);
 
-		/*
-		 * Fetch the checksum array
-		 * Maybe we want to do this a bit cleaner ;)
-		 */
-		$status = $parsed[0]['value'][1]['value'][1]['value'];
-		$expectedStatus = 'HTTP/1.1 404 Not Found';
-		Assert::assertEquals(
-			$expectedStatus,
-			$status,
-			"Expected status to be $expectedStatus but got $status"
+		Assert::assertNotEmpty(
+			$headerChecksums,
+			__METHOD__ . " getHeader('OC-Checksum') returned an empty array. No checksum header was found."
 		);
-	}
 
-	/**
-	 * @Then the OC-Checksum header should not be there
-	 *
-	 * @return void
-	 * @throws Exception
-	 */
-	public function theOcChecksumHeaderShouldNotBeThere():void {
-		$isHeader = $this->featureContext->getResponse()->hasHeader('OC-Checksum');
-		Assert::assertFalse(
-			$isHeader,
-			"Expected no checksum header but got "
-			. print_r($this->featureContext->getResponse()->getHeader('OC-Checksum'), true)
+		$checksumCount = \count($headerChecksums);
+
+		Assert::assertTrue(
+			$checksumCount === 1,
+			__METHOD__ . " Expected 1 checksum in the header but found $checksumCount checksums"
+		);
+
+		$headerChecksum
+			= $headerChecksums[0];
+		Assert::assertEquals(
+			$expectedChecksum,
+			$headerChecksum,
+			"Expected: header checksum should match $expectedChecksum but got $headerChecksum"
 		);
 	}
 
diff --git a/tests/acceptance/features/bootstrap/SpacesContext.php b/tests/acceptance/features/bootstrap/SpacesContext.php
index e22a77908be..26ec049686f 100644
--- a/tests/acceptance/features/bootstrap/SpacesContext.php
+++ b/tests/acceptance/features/bootstrap/SpacesContext.php
@@ -3098,7 +3098,7 @@ class SpacesContext implements Context {
 		string $spaceName
 	): void {
 		$this->setSpaceIDByName($user, $spaceName);
-		$this->checksumContext->userRequestsTheChecksumOfViaPropfind($user, $path);
+		$this->featureContext->setResponse($this->checksumContext->propfindResourceChecksum($user, $path));
 	}
 
 	/**
diff --git a/tests/acceptance/features/bootstrap/TrashbinContext.php b/tests/acceptance/features/bootstrap/TrashbinContext.php
index f8eeb2645b8..d64be8567c8 100644
--- a/tests/acceptance/features/bootstrap/TrashbinContext.php
+++ b/tests/acceptance/features/bootstrap/TrashbinContext.php
@@ -850,7 +850,7 @@ class TrashbinContext implements Context {
 	}
 
 	/**
-	 * @When user :user restores the folder with original path :originalPath without specifying the destination using the trashbin API
+	 * @When user :user restores the folder/file with original path :originalPath without specifying the destination using the trashbin API
 	 *
 	 * @param $user string
 	 * @param $originalPath string
diff --git a/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature b/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature
index cc433c272ef..d6ee3c2df25 100644
--- a/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature
+++ b/tests/acceptance/features/coreApiFavorites/favoritesSharingToShares.feature
@@ -13,7 +13,12 @@ Feature: favorite
   Scenario Outline: favorite a file inside of a received share
     Given using <dav-path-version> DAV path
     And user "Brian" has been created with default attributes and without skeleton files
-    And user "Alice" has shared folder "/PARENT" with user "Brian"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | PARENT   |
+      | space           | Personal |
+      | sharee          | Brian    |
+      | shareType       | user     |
+      | permissionsRole | Editor   |
     When user "Brian" favorites element "/Shares/PARENT/parent.txt" using the WebDAV API
     Then the HTTP status code should be "207"
     And as user "Brian" file "/Shares/PARENT/parent.txt" should be favorited
@@ -27,7 +32,12 @@ Feature: favorite
     Given using <dav-path-version> DAV path
     And user "Brian" has been created with default attributes and without skeleton files
     And user "Alice" has created folder "/PARENT/sub-folder"
-    And user "Alice" has shared folder "/PARENT" with user "Brian"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | PARENT   |
+      | space           | Personal |
+      | sharee          | Brian    |
+      | shareType       | user     |
+      | permissionsRole | Editor   |
     When user "Brian" favorites element "/Shares/PARENT/sub-folder" using the WebDAV API
     Then the HTTP status code should be "207"
     And as user "Brian" folder "/Shares/PARENT/sub-folder" should be favorited
@@ -40,7 +50,12 @@ Feature: favorite
   Scenario Outline: favorite a received share itself
     Given using <dav-path-version> DAV path
     And user "Brian" has been created with default attributes and without skeleton files
-    And user "Alice" has shared folder "/PARENT" with user "Brian"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | PARENT   |
+      | space           | Personal |
+      | sharee          | Brian    |
+      | shareType       | user     |
+      | permissionsRole | Editor   |
     When user "Brian" favorites element "/Shares/PARENT" using the WebDAV API
     Then the HTTP status code should be "207"
     And as user "Brian" folder "/Shares/PARENT" should be favorited
@@ -53,7 +68,12 @@ Feature: favorite
   Scenario Outline: moving a favorite file out of a share keeps favorite state
     Given using <dav-path-version> DAV path
     And user "Brian" has been created with default attributes and without skeleton files
-    And user "Alice" has shared folder "/PARENT" with user "Brian"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | PARENT   |
+      | space           | Personal |
+      | sharee          | Brian    |
+      | shareType       | user     |
+      | permissionsRole | Editor   |
     And user "Brian" has favorited element "/Shares/PARENT/parent.txt"
     When user "Brian" moves file "/Shares/PARENT/parent.txt" to "/taken_out.txt" using the WebDAV API
     Then the HTTP status code should be "201"
@@ -68,7 +88,12 @@ Feature: favorite
   Scenario Outline: sharee file favorite state should not change the favorite state of sharer
     Given using <dav-path-version> DAV path
     And user "Brian" has been created with default attributes and without skeleton files
-    And user "Alice" has shared file "/PARENT/parent.txt" with user "Brian"
+    And user "Alice" has sent the following resource share invitation:
+      | resource        | PARENT/parent.txt |
+      | space           | Personal          |
+      | sharee          | Brian             |
+      | shareType       | user              |
+      | permissionsRole | File Editor       |
     When user "Brian" favorites element "/Shares/parent.txt" using the WebDAV API
     Then the HTTP status code should be "207"
     And as user "Brian" file "/Shares/parent.txt" should be favorited
diff --git a/tests/acceptance/features/coreApiTrashbin/trashbinFilesFolders.feature b/tests/acceptance/features/coreApiTrashbin/trashbinFilesFolders.feature
index 039951792a7..478daa2507b 100644
--- a/tests/acceptance/features/coreApiTrashbin/trashbinFilesFolders.feature
+++ b/tests/acceptance/features/coreApiTrashbin/trashbinFilesFolders.feature
@@ -376,12 +376,24 @@ Feature: files and folders exist in the trashbin after being deleted
       | !@tester$^.txt   |
       | %file *?2.txt    |
       | # %ab ab?=ed.txt |
+      | fo.              |
+      | fo.1             |
+      | fo...1..         |
+      | ...              |
+      | ..fo             |
+      | fo.xyz           |
     When user "Alice" deletes the following files
       | path             |
       | qa&dev.txt       |
       | !@tester$^.txt   |
       | %file *?2.txt    |
       | # %ab ab?=ed.txt |
+      | fo.              |
+      | fo.1             |
+      | fo...1..         |
+      | ...              |
+      | ..fo             |
+      | fo.xyz           |
     Then the HTTP status code of responses on all endpoints should be "204"
     And as "Alice" the following files should not exist
       | path             |
@@ -389,12 +401,24 @@ Feature: files and folders exist in the trashbin after being deleted
       | !@tester$^.txt   |
       | %file *?2.txt    |
       | # %ab ab?=ed.txt |
+      | fo.              |
+      | fo.1             |
+      | fo...1..         |
+      | ...              |
+      | ..fo             |
+      | fo.xyz           |
     But as "Alice" the files with following original paths should exist in the trashbin
       | path             |
       | qa&dev.txt       |
       | !@tester$^.txt   |
       | %file *?2.txt    |
       | # %ab ab?=ed.txt |
+      | fo.              |
+      | fo.1             |
+      | fo...1..         |
+      | ...              |
+      | ..fo             |
+      | fo.xyz           |
     Examples:
       | dav-path-version |
       | new              |
@@ -413,12 +437,24 @@ Feature: files and folders exist in the trashbin after being deleted
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | fo.          |
+      | fo.1         |
+      | fo...1..     |
+      | ...          |
+      | ..fo         |
+      | fo.xyz       |
     When user "Alice" deletes the following folders
       | path         |
       | qa&dev       |
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | fo.          |
+      | fo.1         |
+      | fo...1..     |
+      | ...          |
+      | ..fo         |
+      | fo.xyz       |
     Then the HTTP status code of responses on all endpoints should be "204"
     But as "Alice" the following folders should not exist
       | path         |
@@ -426,12 +462,24 @@ Feature: files and folders exist in the trashbin after being deleted
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | fo.          |
+      | fo.1         |
+      | fo...1..     |
+      | ...          |
+      | ..fo         |
+      | fo.xyz       |
     And as "Alice" the folders with following original paths should exist in the trashbin
       | path         |
       | qa&dev       |
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | fo.          |
+      | fo.1         |
+      | fo...1..     |
+      | ...          |
+      | ..fo         |
+      | fo.xyz       |
     Examples:
       | dav-path-version |
       | new              |
diff --git a/tests/acceptance/features/coreApiTrashbinRestore/trashbinRestore.feature b/tests/acceptance/features/coreApiTrashbinRestore/trashbinRestore.feature
index 6d9c9dbd2ee..e2fd73663a3 100644
--- a/tests/acceptance/features/coreApiTrashbinRestore/trashbinRestore.feature
+++ b/tests/acceptance/features/coreApiTrashbinRestore/trashbinRestore.feature
@@ -187,10 +187,10 @@ Feature: restore deleted files/folders
     And the content of file "<file-name>" for user "Alice" should be "file original content"
     Examples:
       | dav-path-version | file-name               |
-      | old              | 😛 😜 🐱 🐭 ⌚️ ♀️ 🚴‍♂️ |
-      | new              | 😛 😜 🐱 🐭 ⌚️ ♀️ 🚴‍♂️ |
-      | old              | strängé नेपाली file     |
-      | new              | strängé नेपाली file     |
+      | old              | 😛 😜 🐱 🐭 ⌚️ ♀️ 🚴‍♂️    |
+      | new              | 😛 😜 🐱 🐭 ⌚️ ♀️ 🚴‍♂️    |
+      | old              | strängé नेपाली file       |
+      | new              | strängé नेपाली file       |
       | old              | sample,1.txt            |
       | new              | sample,1.txt            |
 
@@ -352,18 +352,21 @@ Feature: restore deleted files/folders
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | Folder,Comma |
     And user "Alice" has deleted the following folders
       | path         |
       | qa&dev       |
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | Folder,Comma |
     When user "Alice" restores the following folders with original path
       | path         |
       | qa&dev       |
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | Folder,Comma |
     Then the HTTP status code of responses on all endpoints should be "201"
     And as "Alice" the folders with following original paths should not exist in the trashbin
       | path         |
@@ -371,12 +374,14 @@ Feature: restore deleted files/folders
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | Folder,Comma |
     But as "Alice" the following folders should exist
       | path         |
       | qa&dev       |
       | !@tester$^   |
       | %file *?2    |
       | # %ab ab?=ed |
+      | Folder,Comma |
     Examples:
       | dav-path-version |
       | old              |
@@ -389,7 +394,7 @@ Feature: restore deleted files/folders
     And user "Alice" has created folder "/parent_folder/sub"
     And user "Alice" has uploaded file with content "parent text" to "/parent_folder/sub/parent.txt"
     And user "Alice" has deleted folder "parent_folder"
-    When user "Alice" restores the folder with original path "/parent_folder/sub/parent.txt" to "parent.txt" using the trashbin API
+    When user "Alice" restores the file with original path "/parent_folder/sub/parent.txt" to "parent.txt" using the trashbin API
     Then the HTTP status code should be "201"
     And the following headers should match these regular expressions for user "Alice"
       | ETag | /^"[a-f0-9:\.]{1,32}"$/ |
@@ -407,7 +412,7 @@ Feature: restore deleted files/folders
     And user "Alice" has created folder "/parent_folder/sub"
     And user "Alice" has uploaded file with content "parent text" to "/parent_folder/sub/parent.txt"
     And user "Alice" has deleted folder "parent_folder"
-    When user "Alice" restores the folder with original path "/parent_folder/sub/parent.txt" to "/parent_folder/sub/parent.txt" using the trashbin API
+    When user "Alice" restores the file with original path "/parent_folder/sub/parent.txt" to "/parent_folder/sub/parent.txt" using the trashbin API
     Then the HTTP status code should be "409"
     And as "Alice" the file with original path "/parent_folder/sub/parent.txt" should exist in the trashbin
     And user "Alice" should not see the following elements
@@ -428,7 +433,7 @@ Feature: restore deleted files/folders
     And user "Alice" has deleted folder "parent_folder"
     And user "Alice" has created folder "/parent_folder"
     And user "Alice" has created folder "/parent_folder/sub"
-    When user "Alice" restores the folder with original path "/parent_folder/sub/parent.txt" using the trashbin API
+    When user "Alice" restores the file with original path "/parent_folder/sub/parent.txt" using the trashbin API
     Then the HTTP status code should be "201"
     And the following headers should match these regular expressions for user "Alice"
       | ETag | /^"[a-f0-9:\.]{1,32}"$/ |
@@ -450,7 +455,7 @@ Feature: restore deleted files/folders
     And user "Alice" has created folder "/parent_folder/sub"
     And user "Alice" has uploaded file with content "parent text" to "/parent_folder/sub/parent.txt"
     And user "Alice" has deleted folder "parent_folder"
-    When user "Alice" restores the folder with original path "/parent_folder/sub/parent.txt" without specifying the destination using the trashbin API
+    When user "Alice" restores the file with original path "/parent_folder/sub/parent.txt" without specifying the destination using the trashbin API
     Then the HTTP status code should be "400"
     And as "Alice" the file with original path "/parent_folder/sub/parent.txt" should exist in the trashbin
     And user "Alice" should not see the following elements
@@ -467,7 +472,7 @@ Feature: restore deleted files/folders
     Given using <dav-path-version> DAV path
     And user "Alice" has uploaded file with content "parent text" to "/parent.txt"
     And user "Alice" has deleted file "parent.txt"
-    When user "Alice" restores the folder with original path "parent.txt" without specifying the destination using the trashbin API
+    When user "Alice" restores the file with original path "parent.txt" without specifying the destination using the trashbin API
     Then the HTTP status code should be "400"
     And as "Alice" the file with original path "parent.txt" should exist in the trashbin
     And user "Alice" should not see the following elements
@@ -530,3 +535,35 @@ Feature: restore deleted files/folders
       | dav-path-version |
       | old              |
       | new              |
+
+
+  Scenario Outline: restore deleted file when folder with same name exists
+    Given using <dav-path-version> DAV path
+    And user "Alice" has uploaded file with content "lorem epsum" to "same-name.txt"
+    And user "Alice" has deleted file "same-name.txt"
+    And user "Alice" has created folder "same-name.txt"
+    When user "Alice" restores the file with original path "same-name.txt" using the trashbin API
+    Then the HTTP status code should be "204"
+    And the content of file "same-name.txt" for user "Alice" should be "lorem epsum"
+    And as "Alice" folder "same-name.txt" should not exist
+    And as "Alice" the folder with original path "same-name.txt" should exist in the trashbin
+    Examples:
+      | dav-path-version |
+      | old              |
+      | new              |
+
+
+  Scenario Outline: restore deleted folder when file with same name exists
+    Given using <dav-path-version> DAV path
+    And user "Alice" has created folder "same-name.txt"
+    And user "Alice" has deleted folder "same-name.txt"
+    And user "Alice" has uploaded file with content "lorem epsum" to "same-name.txt"
+    When user "Alice" restores the folder with original path "same-name.txt" using the trashbin API
+    Then the HTTP status code should be "204"
+    And as "Alice" folder "same-name.txt" should exist
+    And as "Alice" file "same-name.txt" should not exist
+    And as "Alice" the file with original path "same-name.txt" should exist in the trashbin
+    Examples:
+      | dav-path-version |
+      | old              |
+      | new              |
diff --git a/tests/acceptance/features/coreApiWebdavDelete/deleteFile.feature b/tests/acceptance/features/coreApiWebdavDelete/deleteFile.feature
index 3a856f5cd5b..eadfb869089 100644
--- a/tests/acceptance/features/coreApiWebdavDelete/deleteFile.feature
+++ b/tests/acceptance/features/coreApiWebdavDelete/deleteFile.feature
@@ -103,6 +103,32 @@ Feature: delete file
       | spaces           | ",,,.,"        |
 
 
+  Scenario Outline: delete a file with special characters in the filename
+    Given using <dav-path-version> DAV path
+    And user "Alice" has uploaded file with content "special file" to <file-name>
+    When user "Alice" deletes file <file-name> using the WebDAV API
+    Then the HTTP status code should be "204"
+    And as "Alice" file <file-name> should not exist
+    Examples:
+      | dav-path-version | file-name      |
+      | old              | "'single'.txt" |
+      | old              | '"double".txt' |
+      | old              | "question?"    |
+      | old              | "&and#hash"    |
+      | new              | "'single'.txt" |
+      | new              | '"double".txt' |
+      | new              | "question?"    |
+      | new              | "&and#hash"    |
+
+    @skipOnRevaMaster
+    Examples:
+      | dav-path-version | file-name      |
+      | spaces           | "'single'.txt" |
+      | spaces           | '"double".txt' |
+      | spaces           | "question?"    |
+      | spaces           | "&and#hash"    |
+
+
   Scenario Outline: delete a hidden file
     Given using <dav-path-version> DAV path
     And user "Alice" has created folder "/FOLDER"