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
+9 -7
View File
@@ -47,13 +47,15 @@ type TokenManager struct {
// Config combines all available configuration parts. // Config combines all available configuration parts.
type Config struct { type Config struct {
File string File string
Log Log Log Log
Debug Debug Debug Debug
HTTP HTTP HTTP HTTP
Tracing Tracing Tracing Tracing
TokenManager TokenManager TokenManager TokenManager
Service Service Service Service
AccountBackend string
RevaAddress string
Context context.Context Context context.Context
Supervised bool Supervised bool
+15
View File
@@ -150,6 +150,21 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
EnvVars: []string{"OCS_JWT_SECRET", "OCIS_JWT_SECRET"}, EnvVars: []string{"OCS_JWT_SECRET", "OCIS_JWT_SECRET"},
Destination: &cfg.TokenManager.JWTSecret, 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,
},
} }
} }
+7
View File
@@ -10,6 +10,7 @@ import (
"github.com/go-chi/chi/middleware" "github.com/go-chi/chi/middleware"
"github.com/go-chi/render" "github.com/go-chi/render"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0" accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/account" "github.com/owncloud/ocis/ocis-pkg/account"
"github.com/owncloud/ocis/ocis-pkg/log" "github.com/owncloud/ocis/ocis-pkg/log"
@@ -19,6 +20,7 @@ import (
ocsm "github.com/owncloud/ocis/ocs/pkg/middleware" 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/data"
"github.com/owncloud/ocis/ocs/pkg/service/v0/response" "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" 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) 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 { func (o Ocs) getGroupsService() accounts.GroupsService {
return accounts.NewGroupsService("com.owncloud.api.accounts", grpc.DefaultClient) return accounts.NewGroupsService("com.owncloud.api.accounts", grpc.DefaultClient)
} }
+130 -56
View File
@@ -34,27 +34,19 @@ func (o Ocs) GetSelf(w http.ResponseWriter, r *http.Request) {
return return
} }
account, err = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{ switch o.config.AccountBackend {
Id: u.Id.OpaqueId, 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 { if err != nil {
merr := merrors.FromError(err) 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") o.logger.Error().Err(merr).Interface("user", u).Msg("could not get account for user")
return return
} }
@@ -83,39 +75,23 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
var account *accounts.Account var account *accounts.Account
var err error var err error
if userid == "" { switch {
case userid == "":
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "missing user in context"))) 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) 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 { if err != nil {
merr := merrors.FromError(err) merr := merrors.FromError(err)
u, ok := user.ContextGetUser(r.Context()) if merr.Code == http.StatusNotFound {
if !ok || u.Id == nil || u.Id.OpaqueId == "" { mustNotFail(render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found")))
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "user is missing an id"))) } else {
return mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error())))
}
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
} }
o.logger.Error().Err(merr).Str("userid", userid).Msg("could not get account for user") o.logger.Error().Err(merr).Str("userid", userid).Msg("could not get account for user")
return return
@@ -212,9 +188,20 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
newAccount.GidNumber = gidNumber newAccount.GidNumber = gidNumber
} }
account, err := o.getAccountService().CreateAccount(r.Context(), &accounts.CreateAccountRequest{ var account *accounts.Account
Account: newAccount, 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 { if err != nil {
merr := merrors.FromError(err) merr := merrors.FromError(err)
switch merr.Code { switch merr.Code {
@@ -263,7 +250,18 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
// EditUser creates a new user account // EditUser creates a new user account
func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) { func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid") 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 { if err != nil {
merr := merrors.FromError(err) merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound { if merr.Code == http.StatusNotFound {
@@ -330,7 +328,18 @@ func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
// DeleteUser deletes a user // DeleteUser deletes a user
func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) { func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid") 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 { if err != nil {
merr := merrors.FromError(err) merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound { if merr.Code == http.StatusNotFound {
@@ -365,7 +374,18 @@ func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) {
// EnableUser enables a user // EnableUser enables a user
func (o Ocs) EnableUser(w http.ResponseWriter, r *http.Request) { func (o Ocs) EnableUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid") 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 { if err != nil {
merr := merrors.FromError(err) merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound { if merr.Code == http.StatusNotFound {
@@ -405,7 +425,18 @@ func (o Ocs) EnableUser(w http.ResponseWriter, r *http.Request) {
// DisableUser disables a user // DisableUser disables a user
func (o Ocs) DisableUser(w http.ResponseWriter, r *http.Request) { func (o Ocs) DisableUser(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid") 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 { if err != nil {
merr := merrors.FromError(err) merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound { 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)) query = fmt.Sprintf("on_premises_sam_account_name eq '%s'", escapeValue(search))
} }
res, err := o.getAccountService().ListAccounts(r.Context(), &accounts.ListAccountsRequest{ var res *accounts.ListAccountsResponse
Query: query, 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 { if err != nil {
o.logger.Err(err).Msg("could not list users") o.logger.Err(err).Msg("could not list users")
mustNotFail(render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, "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") 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) { func (o Ocs) extractUIDAndGID(u *cs3.User) (int64, int64) {
var uid, gid int64 var uid, gid int64
var err error var err error