Make accounts backend configurable in ocs

This commit is contained in:
Ishank Arora
2021-04-13 13:28:19 +02:00
parent 1b0b14512c
commit 9a2a3bf229
4 changed files with 161 additions and 63 deletions

View File

@@ -47,13 +47,15 @@ type TokenManager struct {
// Config combines all available configuration parts.
type Config struct {
File string
Log Log
Debug Debug
HTTP HTTP
Tracing Tracing
TokenManager TokenManager
Service Service
File string
Log Log
Debug Debug
HTTP HTTP
Tracing Tracing
TokenManager TokenManager
Service Service
AccountBackend string
RevaAddress string
Context context.Context
Supervised bool

View File

@@ -150,6 +150,21 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
EnvVars: []string{"OCS_JWT_SECRET", "OCIS_JWT_SECRET"},
Destination: &cfg.TokenManager.JWTSecret,
},
&cli.StringFlag{
Name: "account-backend-type",
Value: flags.OverrideDefaultString(cfg.AccountBackend, "accounts"),
Usage: "account-backend-type",
EnvVars: []string{"OCS_ACCOUNT_BACKEND_TYPE"},
Destination: &cfg.AccountBackend,
},
&cli.StringFlag{
Name: "reva-gateway-addr",
Value: flags.OverrideDefaultString(cfg.RevaAddress, "127.0.0.1:9142"),
Usage: "REVA Gateway Endpoint",
EnvVars: []string{"OCS_REVA_GATEWAY_ADDR"},
Destination: &cfg.RevaAddress,
},
}
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/go-chi/chi/middleware"
"github.com/go-chi/render"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/account"
"github.com/owncloud/ocis/ocis-pkg/log"
@@ -19,6 +20,7 @@ import (
ocsm "github.com/owncloud/ocis/ocs/pkg/middleware"
"github.com/owncloud/ocis/ocs/pkg/service/v0/data"
"github.com/owncloud/ocis/ocs/pkg/service/v0/response"
"github.com/owncloud/ocis/proxy/pkg/user/backend"
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
)
@@ -154,6 +156,11 @@ func (o Ocs) getAccountService() accounts.AccountsService {
return accounts.NewAccountsService("com.owncloud.api.accounts", grpc.DefaultClient)
}
func (o Ocs) getCS3Backend() backend.UserBackend {
revaClient, err := cs3.GetGatewayServiceClient(o.config.RevaAddress)
return backend.NewCS3UserBackend(revaClient, nil, revaClient, o.logger)
}
func (o Ocs) getGroupsService() accounts.GroupsService {
return accounts.NewGroupsService("com.owncloud.api.accounts", grpc.DefaultClient)
}

View File

@@ -34,27 +34,19 @@ func (o Ocs) GetSelf(w http.ResponseWriter, r *http.Request) {
return
}
account, err = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
Id: u.Id.OpaqueId,
})
switch o.config.AccountBackend {
case "accounts":
account, err = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
Id: u.Id.OpaqueId,
})
case "cs3":
account, err = o.fetchAccountFromCS3BackendByID(r.Context(), u.Id)
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
merr := merrors.FromError(err)
// TODO(someone) this fix is in place because if the user backend (PROXY_ACCOUNT_BACKEND_TYPE) is set to, for instance,
// cs3, we cannot count with the accounts service.
if u != nil {
uid, gid := o.extractUIDAndGID(u)
d := &data.User{
UserID: u.Username,
DisplayName: u.DisplayName,
LegacyDisplayName: u.DisplayName,
Email: u.Mail,
UIDNumber: uid,
GIDNumber: gid,
}
mustNotFail(render.Render(w, r, response.DataRender(d)))
return
}
o.logger.Error().Err(merr).Interface("user", u).Msg("could not get account for user")
return
}
@@ -83,39 +75,23 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
var account *accounts.Account
var err error
if userid == "" {
switch {
case userid == "":
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "missing user in context")))
} else {
case o.config.AccountBackend == "accounts":
account, err = o.fetchAccountByUsername(r.Context(), userid)
case o.config.AccountBackend == "cs3":
account, err = o.fetchAccountFromCS3BackendByUsername(r.Context(), userid)
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
merr := merrors.FromError(err)
u, ok := user.ContextGetUser(r.Context())
if !ok || u.Id == nil || u.Id.OpaqueId == "" {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "user is missing an id")))
return
}
if u != nil {
uid, gid := o.extractUIDAndGID(u)
d := &data.User{
UserID: u.Username,
DisplayName: u.DisplayName,
LegacyDisplayName: u.DisplayName,
Email: u.Mail,
UIDNumber: uid,
GIDNumber: gid,
Enabled: "true", // Assume true for CS3 backend?
// TODO query storage registry for free space? of home storage, maybe...
Quota: &data.Quota{
Free: 2840756224000,
Used: 5059416668,
Total: 2845815640668,
Relative: 0.18,
Definition: "default",
},
}
mustNotFail(render.Render(w, r, response.DataRender(d)))
return
if merr.Code == http.StatusNotFound {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found")))
} else {
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error())))
}
o.logger.Error().Err(merr).Str("userid", userid).Msg("could not get account for user")
return
@@ -212,9 +188,20 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
newAccount.GidNumber = gidNumber
}
account, err := o.getAccountService().CreateAccount(r.Context(), &accounts.CreateAccountRequest{
Account: newAccount,
})
var account *accounts.Account
var err error
switch o.config.AccountBackend {
case "accounts":
account, err = o.getAccountService().CreateAccount(r.Context(), &accounts.CreateAccountRequest{
Account: newAccount,
})
case "cs3":
o.logger.Fatal().Msg("cs3 backend doesn't support adding users")
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
merr := merrors.FromError(err)
switch merr.Code {
@@ -263,7 +250,18 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
// EditUser creates a new user account
func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid")
account, err := o.fetchAccountByUsername(r.Context(), userid)
var account *accounts.Account
var err error
switch o.config.AccountBackend {
case "accounts":
account, err := o.fetchAccountByUsername(r.Context(), userid)
case "cs3":
o.logger.Fatal().Msg("cs3 backend doesn't support editing users")
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
@@ -330,7 +328,18 @@ func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
// DeleteUser deletes a user
func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid")
account, err := o.fetchAccountByUsername(r.Context(), userid)
var account *accounts.Account
var err error
switch o.config.AccountBackend {
case "accounts":
account, err := o.fetchAccountByUsername(r.Context(), userid)
case "cs3":
o.logger.Fatal().Msg("cs3 backend doesn't support deleting users")
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
@@ -365,7 +374,18 @@ func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) {
// EnableUser enables a user
func (o Ocs) EnableUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid")
account, err := o.fetchAccountByUsername(r.Context(), userid)
var account *accounts.Account
var err error
switch o.config.AccountBackend {
case "accounts":
account, err := o.fetchAccountByUsername(r.Context(), userid)
case "cs3":
o.logger.Fatal().Msg("cs3 backend doesn't support enabling users")
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
@@ -405,7 +425,18 @@ func (o Ocs) EnableUser(w http.ResponseWriter, r *http.Request) {
// DisableUser disables a user
func (o Ocs) DisableUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid")
account, err := o.fetchAccountByUsername(r.Context(), userid)
var account *accounts.Account
var err error
switch o.config.AccountBackend {
case "accounts":
account, err := o.fetchAccountByUsername(r.Context(), userid)
case "cs3":
o.logger.Fatal().Msg("cs3 backend doesn't support disabling users")
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
@@ -522,9 +553,20 @@ func (o Ocs) ListUsers(w http.ResponseWriter, r *http.Request) {
query = fmt.Sprintf("on_premises_sam_account_name eq '%s'", escapeValue(search))
}
res, err := o.getAccountService().ListAccounts(r.Context(), &accounts.ListAccountsRequest{
Query: query,
})
var res *accounts.ListAccountsResponse
var err error
switch o.config.AccountBackend {
case "accounts":
res, err = o.getAccountService().ListAccounts(r.Context(), &accounts.ListAccountsRequest{
Query: query,
})
case "cs3":
// TODO
o.logger.Fatal().Msg("cs3 backend doesn't support listing users")
default:
o.logger.Fatal().Msgf("Invalid accounts backend type '%s'", o.config.AccountBackend)
}
if err != nil {
o.logger.Err(err).Msg("could not list users")
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, "could not list users")))
@@ -558,6 +600,38 @@ func (o Ocs) fetchAccountByUsername(ctx context.Context, name string) (*accounts
return nil, merrors.NotFound("", "The requested user could not be found")
}
func (o Ocs) fetchAccountFromCS3BackendByUsername(ctx context.Context, name string) (*accounts.Account, error) {
backend := o.getCS3Backend()
u, err := backend.GetUserByClaims(ctx, "username", name, false)
if err != nil {
return nil, err
}
uid, gid := o.extractUIDAndGID(u)
return &accounts.Account{
OnPremisesSamAccountName: u.Username,
DisplayName: u.DisplayName,
Mail: u.Mail,
UIDNumber: uid,
GIDNumber: gid,
}
}
func (o Ocs) fetchAccountFromCS3BackendByID(ctx context.Context, id *cs3.UserId) (*accounts.Account, error) {
backend := o.getCS3Backend()
u, err := backend.GetUser(ctx, id, false)
if err != nil {
return nil, err
}
uid, gid := o.extractUIDAndGID(u)
return &accounts.Account{
OnPremisesSamAccountName: u.Username,
DisplayName: u.DisplayName,
Mail: u.Mail,
UIDNumber: uid,
GIDNumber: gid,
}
}
func (o Ocs) extractUIDAndGID(u *cs3.User) (int64, int64) {
var uid, gid int64
var err error