chore: replace interface with any

This commit is contained in:
Florian Schade
2026-04-23 09:31:11 +02:00
committed by Ralf Haferkamp
parent 8f26149743
commit 288e67cc39
138 changed files with 933 additions and 934 deletions
@@ -7,10 +7,10 @@ import (
"net/http"
"time"
"github.com/jellydator/ttlcache/v3"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
tenantpb "github.com/cs3org/go-cs3apis/cs3/identity/tenant/v1beta1"
rpcpb "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/jellydator/ttlcache/v3"
"github.com/opencloud-eu/opencloud/services/proxy/pkg/router"
"github.com/opencloud-eu/opencloud/services/proxy/pkg/user/backend"
"github.com/opencloud-eu/opencloud/services/proxy/pkg/userroles"
@@ -91,7 +91,7 @@ type accountResolver struct {
eventsPublisher events.Publisher
}
func readStringClaim(path string, claims map[string]interface{}) (string, error) {
func readStringClaim(path string, claims map[string]any) (string, error) {
// happy path
value, _ := claims[path].(string)
if value != "" {
@@ -104,10 +104,10 @@ func readStringClaim(path string, claims map[string]interface{}) (string, error)
lastSegment := len(segments) - 1
for i := range segments {
if i < lastSegment {
if castedClaims, ok := subclaims[segments[i]].(map[string]interface{}); ok {
if castedClaims, ok := subclaims[segments[i]].(map[string]any); ok {
subclaims = castedClaims
} else if castedClaims, ok := subclaims[segments[i]].(map[interface{}]interface{}); ok {
subclaims = make(map[string]interface{}, len(castedClaims))
} else if castedClaims, ok := subclaims[segments[i]].(map[any]any); ok {
subclaims = make(map[string]any, len(castedClaims))
for k, v := range castedClaims {
if s, ok := k.(string); ok {
subclaims[s] = v
@@ -281,7 +281,7 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
m.next.ServeHTTP(w, req)
}
func (m accountResolver) verifyTenantClaim(ctx context.Context, userTenantID string, claims map[string]interface{}) error {
func (m accountResolver) verifyTenantClaim(ctx context.Context, userTenantID string, claims map[string]any) error {
claimTenantID, err := readStringClaim(m.tenantOIDCClaim, claims)
if err != nil {
return fmt.Errorf("could not read tenant claim: %w", err)
@@ -28,13 +28,13 @@ import (
)
const (
testIdP = "https://idx.example.com"
testTenantA = "tenant-a"
testTenantB = "tenant-b"
testJWTSecret = "change-me"
testSvcAccountID = "svc-account-id"
testSvcAccountSecret = "svc-account-secret"
testSvcAccountToken = "svc-account-token"
testIdP = "https://idx.example.com"
testTenantA = "tenant-a"
testTenantB = "tenant-b"
testJWTSecret = "change-me"
testSvcAccountID = "svc-account-id"
testSvcAccountSecret = "svc-account-secret"
testSvcAccountToken = "svc-account-token"
)
func TestTokenIsAddedWithMailClaim(t *testing.T) {
@@ -43,7 +43,7 @@ func TestTokenIsAddedWithMailClaim(t *testing.T) {
Mail: "foo@example.com",
}, nil, oidc.Email, "mail", false)
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
oidc.Email: "foo@example.com",
})
@@ -61,7 +61,7 @@ func TestTokenIsAddedWithUsernameClaim(t *testing.T) {
Mail: "foo@example.com",
}, nil, oidc.PreferredUsername, "username", false)
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
oidc.PreferredUsername: "foo",
})
@@ -81,9 +81,9 @@ func TestTokenIsAddedWithDotUsernamePathClaim(t *testing.T) {
}, nil, "li.un", "username", false)
// This is how lico adds the username to the access token
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
"li": map[string]interface{}{
"li": map[string]any{
"un": "foo",
},
})
@@ -122,7 +122,7 @@ func TestTokenIsAddedWithDottedUsernameClaim(t *testing.T) {
Mail: "foo@example.com",
}, nil, tc.oidcClaim, "username", false)
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
"li.un": "foo",
})
@@ -149,7 +149,7 @@ func TestNSkipOnNoClaims(t *testing.T) {
func TestUnauthorizedOnUserNotFound(t *testing.T) {
sut := newMockAccountResolver(nil, backend.ErrAccountNotFound, oidc.PreferredUsername, "username", false)
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
oidc.PreferredUsername: "foo",
})
@@ -163,7 +163,7 @@ func TestUnauthorizedOnUserNotFound(t *testing.T) {
func TestUnauthorizedOnUserDisabled(t *testing.T) {
sut := newMockAccountResolver(nil, backend.ErrAccountDisabled, oidc.PreferredUsername, "username", false)
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
oidc.PreferredUsername: "foo",
})
@@ -177,7 +177,7 @@ func TestUnauthorizedOnUserDisabled(t *testing.T) {
func TestInternalServerErrorOnMissingMailAndUsername(t *testing.T) {
sut := newMockAccountResolver(nil, backend.ErrAccountNotFound, oidc.Email, "mail", false)
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
})
@@ -262,7 +262,7 @@ func TestTenantClaimValidation(t *testing.T) {
Username: "foo",
}
tokenManager, _ := jwt.New(map[string]interface{}{"secret": testJWTSecret, "expires": int64(60)})
tokenManager, _ := jwt.New(map[string]any{"secret": testJWTSecret, "expires": int64(60)})
s, _ := scope.AddOwnerScope(nil)
token, _ := tokenManager.MintToken(context.Background(), user, s)
@@ -281,7 +281,7 @@ func TestTenantClaimValidation(t *testing.T) {
MultiTenantEnabled(true),
)(mockHandler{})
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
oidc.PreferredUsername: "foo",
"tenant_id": tc.requestTenant,
@@ -300,7 +300,7 @@ func TestTenantClaimValidation(t *testing.T) {
}
func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr error, oidcclaim, cs3claim string, multiTenant bool) http.Handler {
tokenManager, _ := jwt.New(map[string]interface{}{
tokenManager, _ := jwt.New(map[string]any{
"secret": testJWTSecret,
"expires": int64(60),
})
@@ -330,7 +330,7 @@ func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr
)(mockHandler{})
}
func mockRequest(claims map[string]interface{}) (*http.Request, *httptest.ResponseRecorder) {
func mockRequest(claims map[string]any) (*http.Request, *httptest.ResponseRecorder) {
if claims == nil {
return httptest.NewRequest("GET", "http://example.com/foo", nil), httptest.NewRecorder()
}
@@ -362,7 +362,7 @@ func TestTenantIDMapping(t *testing.T) {
Username: "foo",
}
tokenManager, _ := jwt.New(map[string]interface{}{"secret": testJWTSecret, "expires": int64(60)})
tokenManager, _ := jwt.New(map[string]any{"secret": testJWTSecret, "expires": int64(60)})
s, _ := scope.AddOwnerScope(nil)
token, _ := tokenManager.MintToken(context.Background(), user, s)
@@ -449,7 +449,7 @@ func TestTenantIDMapping(t *testing.T) {
Value: externalTenantID,
}).Return(tc.tenantResponse, nil)
req, rw := mockRequest(map[string]interface{}{
req, rw := mockRequest(map[string]any{
oidc.Iss: testIdP,
oidc.PreferredUsername: "foo",
"tenant_id": externalTenantID,
@@ -126,7 +126,7 @@ var _ = Describe("Authenticating requests", Label("Authentication"), func() {
EnableBasicAuth(true),
)
testHandler := handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expect(oidc.FromContext(r.Context())).To(Equal(map[string]interface{}{
Expect(oidc.FromContext(r.Context())).To(Equal(map[string]any{
"sid": "a-session-id",
"exp": int64(1147483647),
}))
@@ -144,7 +144,7 @@ var _ = Describe("Authenticating requests", Label("Authentication"), func() {
EnableBasicAuth(true),
)
testHandler := handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expect(oidc.FromContext(r.Context())).To(Equal(map[string]interface{}{
Expect(oidc.FromContext(r.Context())).To(Equal(map[string]any{
"email": "testuser@example.com",
"openclouduuid": "OpaqueId",
"iss": "IdpId",
+1 -1
View File
@@ -41,7 +41,7 @@ func (m BasicAuthenticator) Authenticate(r *http.Request) (*http.Request, bool)
}
// fake oidc claims
claims := map[string]interface{}{
claims := map[string]any{
oidc.Iss: user.Id.Idp,
oidc.PreferredUsername: user.Username,
oidc.Email: user.Mail,
+3 -3
View File
@@ -54,8 +54,8 @@ type OIDCAuthenticator struct {
TimeFunc func() time.Time
}
func (m *OIDCAuthenticator) getClaims(token string, req *http.Request) (map[string]interface{}, bool, error) {
var claims map[string]interface{}
func (m *OIDCAuthenticator) getClaims(token string, req *http.Request) (map[string]any, bool, error) {
var claims map[string]any
// use a 64 bytes long hash to have 256-bit collision resistance.
hash := make([]byte, 64)
@@ -159,7 +159,7 @@ func (m OIDCAuthenticator) extractExpiration(aClaims oidc.RegClaimsWithSID) time
return defaultExpiration
}
func verifyExpiresAt(claims map[string]interface{}, cmp time.Time) bool {
func verifyExpiresAt(claims map[string]any, cmp time.Time) bool {
var expiry time.Time
switch v := claims["exp"].(type) {
case nil:
+2 -2
View File
@@ -35,7 +35,7 @@ type (
Code string `json:"code"`
Message string `json:"message"`
// The structure of this object is service-specific
Innererror map[string]interface{} `json:"innererror,omitempty"`
Innererror map[string]any `json:"innererror,omitempty"`
}
)
@@ -154,7 +154,7 @@ func RenderError(w http.ResponseWriter, r *http.Request, evaluateReq *pService.E
filename = path.Base(evaluateReq.Environment.GetRequest().GetPath())
}
innererror := map[string]interface{}{
innererror := map[string]any{
"date": time.Now().UTC().Format(time.RFC3339),
}
+10 -10
View File
@@ -28,12 +28,12 @@ func loadCSPConfig(presetYamlContent, customYamlContent []byte) (*config.CSP, er
gofig.WithOptions(gofig.ParseEnv)
gofig.AddDriver(yaml.Driver)
presetMap := map[string]interface{}{}
presetMap := map[string]any{}
err := yamlv3.Unmarshal(presetYamlContent, &presetMap)
if err != nil {
return nil, err
}
customMap := map[string]interface{}{}
customMap := map[string]any{}
err = yamlv3.Unmarshal(customYamlContent, &customMap)
if err != nil {
return nil, err
@@ -63,9 +63,9 @@ func loadCSPConfig(presetYamlContent, customYamlContent []byte) (*config.CSP, er
// - nested maps are merged recursively
// - slices are concatenated, preserving order and avoiding duplicates
// - scalar or type-mismatched values from map2 overwrite map1
func deepMerge(map1, map2 map[string]interface{}) map[string]interface{} {
func deepMerge(map1, map2 map[string]any) map[string]any {
if map1 == nil {
out := make(map[string]interface{}, len(map2))
out := make(map[string]any, len(map2))
for k, v := range map2 {
out[k] = v
}
@@ -75,17 +75,17 @@ func deepMerge(map1, map2 map[string]interface{}) map[string]interface{} {
for k, v2 := range map2 {
if v1, ok := map1[k]; ok {
// both maps -> recurse
if m1, ok1 := v1.(map[string]interface{}); ok1 {
if m2, ok2 := v2.(map[string]interface{}); ok2 {
if m1, ok1 := v1.(map[string]any); ok1 {
if m2, ok2 := v2.(map[string]any); ok2 {
map1[k] = deepMerge(m1, m2)
continue
}
}
// both slices -> merge unique
if s1, ok1 := v1.([]interface{}); ok1 {
if s2, ok2 := v2.([]interface{}); ok2 {
merged := append([]interface{}{}, s1...)
if s1, ok1 := v1.([]any); ok1 {
if s2, ok2 := v2.([]any); ok2 {
merged := append([]any{}, s1...)
for _, item := range s2 {
if !sliceContains(merged, item) {
merged = append(merged, item)
@@ -112,7 +112,7 @@ func deepMerge(map1, map2 map[string]interface{}) map[string]interface{} {
return map1
}
func sliceContains(slice []interface{}, val interface{}) bool {
func sliceContains(slice []any, val any) bool {
for _, v := range slice {
if reflect.DeepEqual(v, val) {
return true
@@ -79,10 +79,10 @@ func TestClaimsSelector(t *testing.T) {
var tests = []testCase{
{"unauthenticated", context.Background(), nil, "unauthenticated"},
{"default", oidc.NewContext(context.Background(), map[string]interface{}{oidc.OpenCloudRoutingPolicy: ""}), nil, "default"},
{"claim-value", oidc.NewContext(context.Background(), map[string]interface{}{oidc.OpenCloudRoutingPolicy: "opencloud.routing.policy-value"}), nil, "opencloud.routing.policy-value"},
{"default", oidc.NewContext(context.Background(), map[string]any{oidc.OpenCloudRoutingPolicy: ""}), nil, "default"},
{"claim-value", oidc.NewContext(context.Background(), map[string]any{oidc.OpenCloudRoutingPolicy: "opencloud.routing.policy-value"}), nil, "opencloud.routing.policy-value"},
{"cookie-only", context.Background(), &http.Cookie{Name: SelectorCookieName, Value: "cookie"}, "cookie"},
{"claim-can-override-cookie", oidc.NewContext(context.Background(), map[string]interface{}{oidc.OpenCloudRoutingPolicy: "opencloud.routing.policy-value"}), &http.Cookie{Name: SelectorCookieName, Value: "cookie"}, "opencloud.routing.policy-value"},
{"claim-can-override-cookie", oidc.NewContext(context.Background(), map[string]any{oidc.OpenCloudRoutingPolicy: "opencloud.routing.policy-value"}), &http.Cookie{Name: SelectorCookieName, Value: "cookie"}, "opencloud.routing.policy-value"},
}
for _, tc := range tests {
r := httptest.NewRequest("GET", "https://example.com", nil)
@@ -150,7 +150,7 @@ func (s *StaticRouteHandler) publishBackchannelLogoutEvent(ctx context.Context,
return fmt.Errorf("no claim found for key: %s", claimKey)
}
var claims map[string]interface{}
var claims map[string]any
if err = msgpack.Unmarshal(claimRecords[0].Value, &claims); err != nil {
return fmt.Errorf("failed to unmarshal claims: %w", err)
}
+3 -3
View File
@@ -20,7 +20,7 @@ var (
type UserBackend interface {
GetUserByClaims(ctx context.Context, claim, value string) (*cs3.User, string, error)
Authenticate(ctx context.Context, username string, password string) (*cs3.User, string, error)
CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error)
UpdateUserIfNeeded(ctx context.Context, user *cs3.User, claims map[string]interface{}) error
SyncGroupMemberships(ctx context.Context, user *cs3.User, claims map[string]interface{}) error
CreateUserFromClaims(ctx context.Context, claims map[string]any) (*cs3.User, error)
UpdateUserIfNeeded(ctx context.Context, user *cs3.User, claims map[string]any) error
SyncGroupMemberships(ctx context.Context, user *cs3.User, claims map[string]any) error
}
+6 -6
View File
@@ -11,6 +11,7 @@ import (
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/pkg/oidc"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
@@ -18,7 +19,6 @@ import (
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
utils "github.com/opencloud-eu/reva/v2/pkg/utils"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"go-micro.dev/v4/selector"
)
@@ -161,7 +161,7 @@ func (c *cs3backend) Authenticate(ctx context.Context, username string, password
// attributes from the provided `claims` map. On success it returns the new
// user. If the user already exist this is not considered an error and the
// function will just return the existing user.
func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error) {
func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string]any) (*cs3.User, error) {
gatewayClient, err := c.gatewaySelector.Next()
if err != nil {
c.logger.Error().Err(err).Msg("could not select next gateway client")
@@ -233,7 +233,7 @@ func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string
return &cs3UserCreated, nil
}
func (c cs3backend) UpdateUserIfNeeded(ctx context.Context, user *cs3.User, claims map[string]interface{}) error {
func (c cs3backend) UpdateUserIfNeeded(ctx context.Context, user *cs3.User, claims map[string]any) error {
newUser, err := c.libregraphUserFromClaims(claims)
if err != nil {
c.logger.Error().Err(err).Interface("claims", claims).Msg("Error converting claims to user")
@@ -258,7 +258,7 @@ func (c cs3backend) UpdateUserIfNeeded(ctx context.Context, user *cs3.User, clai
}
// SyncGroupMemberships maintains a users group memberships based on an OIDC claim
func (c cs3backend) SyncGroupMemberships(ctx context.Context, user *cs3.User, claims map[string]interface{}) error {
func (c cs3backend) SyncGroupMemberships(ctx context.Context, user *cs3.User, claims map[string]any) error {
gatewayClient, err := c.gatewaySelector.Next()
if err != nil {
c.logger.Error().Err(err).Msg("could not select next gateway client")
@@ -293,7 +293,7 @@ func (c cs3backend) SyncGroupMemberships(ctx context.Context, user *cs3.User, cl
}
newGroupSet := make(map[string]struct{})
if groups, ok := claims[c.autoProvisionClaims.Groups].([]interface{}); ok {
if groups, ok := claims[c.autoProvisionClaims.Groups].([]any); ok {
for _, g := range groups {
if group, ok := g.(string); ok {
newGroupSet[group] = struct{}{}
@@ -469,7 +469,7 @@ func (c cs3backend) isAlreadyExists(resp *http.Response) (bool, error) {
return false, nil
}
func (c cs3backend) libregraphUserFromClaims(claims map[string]interface{}) (libregraph.User, error) {
func (c cs3backend) libregraphUserFromClaims(claims map[string]any) (libregraph.User, error) {
user := libregraph.User{}
if dn, ok := claims[c.autoProvisionClaims.DisplayName].(string); ok {
user.SetDisplayName(dn)
+1 -1
View File
@@ -29,7 +29,7 @@ func NewDefaultRoleAssigner(opts ...Option) UserRoleAssigner {
// UpdateUserRoleAssignment assigns the role "User" to the supplied user. Unless the user
// already has a different role assigned.
func (d defaultRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]interface{}) (*cs3.User, error) {
func (d defaultRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]any) (*cs3.User, error) {
var roleIDs []string
if user.Id.Type != cs3.UserType_USER_TYPE_LIGHTWEIGHT {
var err error
+3 -3
View File
@@ -30,7 +30,7 @@ func NewOIDCRoleAssigner(opts ...Option) UserRoleAssigner {
}
}
func extractRoles(rolesClaim string, claims map[string]interface{}) (map[string]struct{}, error) {
func extractRoles(rolesClaim string, claims map[string]any) (map[string]struct{}, error) {
claimRoles := map[string]struct{}{}
// happy path
@@ -50,7 +50,7 @@ func extractRoles(rolesClaim string, claims map[string]interface{}) (map[string]
for _, cr := range v {
claimRoles[cr] = struct{}{}
}
case []interface{}:
case []any:
for _, cri := range v {
cr, ok := cri.(string)
if !ok {
@@ -71,7 +71,7 @@ func extractRoles(rolesClaim string, claims map[string]interface{}) (map[string]
// UpdateUserRoleAssignment assigns the role "User" to the supplied user. Unless the user
// already has a different role assigned.
func (ra oidcRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]interface{}) (*cs3.User, error) {
func (ra oidcRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]any) (*cs3.User, error) {
logger := ra.logger.SubloggerWithRequestID(ctx).With().Str("userid", user.GetId().GetOpaqueId()).Logger()
roleNamesToRoleIDs, err := ra.roleNamesToRoleIDs()
if err != nil {
@@ -8,7 +8,7 @@ import (
func TestExtractRolesArray(t *testing.T) {
byt := []byte(`{"roles":["a","b"]}`)
claims := map[string]interface{}{}
claims := map[string]any{}
err := json.Unmarshal(byt, &claims)
if err != nil {
t.Fatal(err)
@@ -29,7 +29,7 @@ func TestExtractRolesArray(t *testing.T) {
func TestExtractRolesString(t *testing.T) {
byt := []byte(`{"roles":"a"}`)
claims := map[string]interface{}{}
claims := map[string]any{}
err := json.Unmarshal(byt, &claims)
if err != nil {
t.Fatal(err)
@@ -47,7 +47,7 @@ func TestExtractRolesString(t *testing.T) {
func TestExtractRolesPathArray(t *testing.T) {
byt := []byte(`{"sub":{"roles":["a","b"]}}`)
claims := map[string]interface{}{}
claims := map[string]any{}
err := json.Unmarshal(byt, &claims)
if err != nil {
t.Fatal(err)
@@ -68,7 +68,7 @@ func TestExtractRolesPathArray(t *testing.T) {
func TestExtractRolesPathString(t *testing.T) {
byt := []byte(`{"sub":{"roles":"a"}}`)
claims := map[string]interface{}{}
claims := map[string]any{}
err := json.Unmarshal(byt, &claims)
if err != nil {
t.Fatal(err)
@@ -86,7 +86,7 @@ func TestExtractRolesPathString(t *testing.T) {
func TestExtractEscapedRolesPathString(t *testing.T) {
byt := []byte(`{"sub.roles":"a"}`)
claims := map[string]interface{}{}
claims := map[string]any{}
err := json.Unmarshal(byt, &claims)
if err != nil {
t.Fatal(err)
@@ -104,7 +104,7 @@ func TestExtractEscapedRolesPathString(t *testing.T) {
func TestNoRoles(t *testing.T) {
byt := []byte(`{"sub":{"foo":"a"}}`)
claims := map[string]interface{}{}
claims := map[string]any{}
err := json.Unmarshal(byt, &claims)
if err != nil {
t.Fatal(err)
+1 -1
View File
@@ -16,7 +16,7 @@ import (
type UserRoleAssigner interface {
// UpdateUserRoleAssignment is called by the account resolver middleware. It updates the user's role assignment
// based on the user's (OIDC) claims. It adds the user's roles to the opaque data of the cs3.User struct
UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]interface{}) (*cs3.User, error)
UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]any) (*cs3.User, error)
// ApplyUserRole can be called by proxy middlewares, it looks up the user's roles and adds them
// the users "roles" key in the user's opaque data
ApplyUserRole(ctx context.Context, user *cs3.User) (*cs3.User, error)