Files
opencloud/proxy/pkg/user/backend/cs3.go
Ralf Haferkamp 6abf38dd3a Fix CreateHome for external users
External users, when logging in for the first time, have no role
assigned and are unable to create their home because that requires the
create-space permission. This assigns users that don't have a role assigned
to the default user role and persists that assignment in the settings
service so that CreateHome can pick it up when checking permissions
later.

This also disables the auto creation of the user's home in the reva
auth provider (i.e. when using basic auth) as the role assignement has
not happenend at that point. So the home creation will now always happen
in the CreateHome middleware in the proxy.
2022-03-16 15:58:19 +01:00

123 lines
3.9 KiB
Go

package backend
import (
"context"
"fmt"
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"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/owncloud/ocis/ocis-pkg/log"
settingssvc "github.com/owncloud/ocis/protogen/gen/ocis/services/settings/v0"
settingsService "github.com/owncloud/ocis/settings/pkg/service/v0"
)
type cs3backend struct {
settingsRoleService settingssvc.RoleService
authProvider RevaAuthenticator
machineAuthAPIKey string
logger log.Logger
}
// NewCS3UserBackend creates a user-provider which fetches users from a CS3 UserBackend
func NewCS3UserBackend(rs settingssvc.RoleService, ap RevaAuthenticator, machineAuthAPIKey string, logger log.Logger) UserBackend {
return &cs3backend{
settingsRoleService: rs,
authProvider: ap,
machineAuthAPIKey: machineAuthAPIKey,
logger: logger,
}
}
func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, string, error) {
res, err := c.authProvider.Authenticate(ctx, &gateway.AuthenticateRequest{
Type: "machine",
ClientId: claim + ":" + value,
ClientSecret: c.machineAuthAPIKey,
})
switch {
case err != nil:
return nil, "", fmt.Errorf("could not get user by claim %v with value %v: %w", claim, value, err)
case res.Status.Code != rpcv1beta1.Code_CODE_OK:
if res.Status.Code == rpcv1beta1.Code_CODE_NOT_FOUND {
return nil, "", ErrAccountNotFound
}
return nil, "", fmt.Errorf("could not get user by claim %v with value %v : %w ", claim, value, err)
}
user := res.User
if !withRoles {
return user, res.Token, nil
}
var roleIDs []string
if user.Id.Type != cs3.UserType_USER_TYPE_LIGHTWEIGHT {
roleIDs, err = loadRolesIDs(ctx, user.Id.OpaqueId, c.settingsRoleService)
if err != nil {
c.logger.Error().Err(err).Msgf("Could not load roles")
}
}
// if roles are empty, assume we haven't seen the user before and assign a
// default user role. At least until proper roles are provided. See
// https://github.com/owncloud/ocis/issues/1825 for more context.
if len(roleIDs) == 0 {
if user.Id.Type == cs3.UserType_USER_TYPE_PRIMARY {
c.logger.Info().Str("userid", user.Id.OpaqueId).Msg("user has no role assigned, assigning default user role")
_, err := c.settingsRoleService.AssignRoleToUser(ctx, &settingssvc.AssignRoleToUserRequest{
AccountUuid: user.Id.OpaqueId,
RoleId: settingsService.BundleUUIDRoleUser,
})
if err != nil {
c.logger.Error().Err(err).Msg("Could not add default role")
}
roleIDs = append(roleIDs, settingsService.BundleUUIDRoleUser)
}
}
enc, err := encodeRoleIDs(roleIDs)
if err != nil {
c.logger.Error().Err(err).Msg("Could not encode loaded roles")
}
if user.Opaque == nil {
user.Opaque = &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"roles": enc,
},
}
} else {
user.Opaque.Map["roles"] = enc
}
return user, res.Token, nil
}
func (c *cs3backend) Authenticate(ctx context.Context, username string, password string) (*cs3.User, string, error) {
res, err := c.authProvider.Authenticate(ctx, &gateway.AuthenticateRequest{
Type: "basic",
ClientId: username,
ClientSecret: password,
})
switch {
case err != nil:
return nil, "", fmt.Errorf("could not authenticate with username and password user: %s, %w", username, err)
case res.Status.Code != rpcv1beta1.Code_CODE_OK:
return nil, "", fmt.Errorf("could not authenticate with username and password user: %s, got code: %d", username, res.Status.Code)
}
return res.User, res.Token, nil
}
func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error) {
return nil, fmt.Errorf("CS3 Backend does not support creating users from claims")
}
func (c cs3backend) GetUserGroups(ctx context.Context, userID string) {
panic("implement me")
}