Merge pull request #117 from owncloud/fix-create-account

Fix create account
This commit is contained in:
Benedikt Kulmann
2020-09-11 16:40:13 +02:00
committed by GitHub
10 changed files with 327 additions and 350 deletions

View File

@@ -0,0 +1,9 @@
Bugfix: Cleanup separated indices in memory
The accounts service was creating a bleve index instance in the service handler, thus creating separate in memory indices for the http and grpc servers. We moved the service handler creation out of the server creation so that the service handler, thus also the bleve index, is a shared instance of the servers.
This fixes a bug that accounts created through the web ui were not able to sign in until a service restart.
https://github.com/owncloud/product/issues/224
https://github.com/owncloud/ocis-accounts/pull/117

View File

@@ -43,6 +43,11 @@ func Server(cfg *config.Config) *cli.Command {
defer cancel()
handler, err := svc.New(svc.Logger(logger), svc.Config(cfg))
if err != nil {
logger.Fatal().Err(err).Msg("could not initialize service handler")
}
{
server := http.Server(
http.Logger(logger),
@@ -52,6 +57,7 @@ func Server(cfg *config.Config) *cli.Command {
http.Metrics(mtrcs),
http.Flags(flagset.RootWithConfig(cfg)),
http.Flags(flagset.ServerWithConfig(cfg)),
http.Handler(handler),
)
gr.Add(server.Run, func(_ error) {
@@ -70,6 +76,7 @@ func Server(cfg *config.Config) *cli.Command {
grpc.Context(ctx),
grpc.Config(cfg),
grpc.Metrics(mtrcs),
grpc.Handler(handler),
)
gr.Add(func() error {

View File

@@ -6,6 +6,7 @@ import (
"github.com/micro/cli/v2"
"github.com/owncloud/ocis-accounts/pkg/config"
"github.com/owncloud/ocis-accounts/pkg/metrics"
svc "github.com/owncloud/ocis-accounts/pkg/service/v0"
"github.com/owncloud/ocis-pkg/v2/log"
)
@@ -20,6 +21,7 @@ type Options struct {
Config *config.Config
Metrics *metrics.Metrics
Flags []cli.Flag
Handler *svc.Service
}
// newOptions initializes the available default options.
@@ -74,3 +76,10 @@ func Flags(val []cli.Flag) Option {
o.Flags = append(o.Flags, val...)
}
}
// Handler provides a function to set the handler option.
func Handler(val *svc.Service) Option {
return func(o *Options) {
o.Handler = val
}
}

View File

@@ -1,19 +1,14 @@
package grpc
import (
"time"
mclient "github.com/micro/go-micro/v2/client"
"github.com/owncloud/ocis-accounts/pkg/proto/v0"
svc "github.com/owncloud/ocis-accounts/pkg/service/v0"
"github.com/owncloud/ocis-pkg/v2/roles"
"github.com/owncloud/ocis-pkg/v2/service/grpc"
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
)
// Server initializes a new go-micro service ready to run
func Server(opts ...Option) grpc.Service {
options := newOptions(opts...)
handler := options.Handler
service := grpc.NewService(
grpc.Name(options.Config.Server.Name),
@@ -24,31 +19,10 @@ func Server(opts ...Option) grpc.Service {
grpc.Flags(options.Flags...),
)
var hdlr *svc.Service
var err error
// TODO this won't work with a registry other than mdns. Look into Micro's client initialization.
// https://github.com/owncloud/ocis-proxy/issues/38
rs := settings.NewRoleService("com.owncloud.api.settings", mclient.DefaultClient)
roleManager := roles.NewManager(
roles.CacheSize(1024),
roles.CacheTTL(time.Hour*24*7),
roles.Logger(options.Logger),
roles.RoleService(rs),
)
if hdlr, err = svc.New(
svc.Logger(options.Logger),
svc.Config(options.Config),
svc.RoleManager(&roleManager),
svc.RoleService(rs),
); err != nil {
options.Logger.Fatal().Err(err).Msg("could not initialize service handler")
}
if err = proto.RegisterAccountsServiceHandler(service.Server(), hdlr); err != nil {
if err := proto.RegisterAccountsServiceHandler(service.Server(), handler); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register service handler")
}
if err = proto.RegisterGroupsServiceHandler(service.Server(), hdlr); err != nil {
if err := proto.RegisterGroupsServiceHandler(service.Server(), handler); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register groups handler")
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/micro/cli/v2"
"github.com/owncloud/ocis-accounts/pkg/config"
"github.com/owncloud/ocis-accounts/pkg/metrics"
svc "github.com/owncloud/ocis-accounts/pkg/service/v0"
"github.com/owncloud/ocis-pkg/v2/log"
)
@@ -20,6 +21,7 @@ type Options struct {
Config *config.Config
Metrics *metrics.Metrics
Flags []cli.Flag
Handler *svc.Service
}
// newOptions initializes the available default options.
@@ -74,3 +76,10 @@ func Flags(val []cli.Flag) Option {
o.Flags = append(o.Flags, val...)
}
}
// Handler provides a function to set the handler option.
func Handler(val *svc.Service) Option {
return func(o *Options) {
o.Handler = val
}
}

View File

@@ -1,24 +1,19 @@
package http
import (
"time"
"github.com/go-chi/chi"
mclient "github.com/micro/go-micro/v2/client"
"github.com/owncloud/ocis-accounts/pkg/assets"
"github.com/owncloud/ocis-accounts/pkg/proto/v0"
svc "github.com/owncloud/ocis-accounts/pkg/service/v0"
"github.com/owncloud/ocis-accounts/pkg/version"
"github.com/owncloud/ocis-pkg/v2/account"
"github.com/owncloud/ocis-pkg/v2/middleware"
"github.com/owncloud/ocis-pkg/v2/roles"
"github.com/owncloud/ocis-pkg/v2/service/http"
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
)
// Server initializes the http service and server.
func Server(opts ...Option) http.Service {
options := newOptions(opts...)
handler := options.Handler
service := http.NewService(
http.Logger(options.Logger),
@@ -30,25 +25,6 @@ func Server(opts ...Option) http.Service {
http.Flags(options.Flags...),
)
// TODO this won't work with a registry other than mdns. Look into Micro's client initialization.
// https://github.com/owncloud/ocis-proxy/issues/38
rs := settings.NewRoleService("com.owncloud.api.settings", mclient.DefaultClient)
roleManager := roles.NewManager(
roles.CacheSize(1024),
roles.CacheTTL(time.Hour*24*7),
roles.Logger(options.Logger),
roles.RoleService(rs),
)
handler, err := svc.New(
svc.Logger(options.Logger),
svc.Config(options.Config),
svc.RoleManager(&roleManager),
svc.RoleService(rs),
)
if err != nil {
options.Logger.Fatal().Err(err).Msg("could not initialize service handler")
}
mux := chi.NewMux()
mux.Use(middleware.RealIP)

View File

@@ -37,28 +37,6 @@ import (
// accLock mutually exclude readers from writers on account files
var accLock sync.Mutex
func (s Service) indexAccounts(path string) (err error) {
var f *os.File
if f, err = os.Open(path); err != nil {
s.log.Error().Err(err).Str("dir", path).Msg("could not open accounts folder")
return
}
list, err := f.Readdir(-1)
f.Close()
if err != nil {
s.log.Error().Err(err).Str("dir", path).Msg("could not list accounts folder")
return
}
for _, file := range list {
err = s.indexAccount(file.Name())
if err != nil {
s.log.Error().Err(err).Str("file", file.Name()).Msg("could not index account")
}
}
return
}
func (s Service) indexAccount(id string) error {
a := &proto.BleveAccount{
BleveType: "account",
@@ -344,29 +322,16 @@ func (s Service) CreateAccount(ctx context.Context, in *proto.CreateAccountReque
// extract group id
// TODO groups should be ignored during create, use groups.AddMember? return error?
// write and index account - note: don't do anything else in between!
if err = s.writeAccount(acc); err != nil {
s.log.Error().Err(err).Str("id", id).Msg("could not persist new account")
s.debugLogAccount(acc).Msg("could not persist new account")
return
}
// TODO: assign user role to all new users for now, as create Account request does not have any role field
if s.RoleService == nil {
return merrors.InternalServerError(s.id, "could not assign role to account: roleService not configured")
}
_, err = s.RoleService.AssignRoleToUser(ctx, &settings.AssignRoleToUserRequest{
AccountUuid: acc.Id,
RoleId: settings_svc.BundleUUIDRoleUser,
})
if err != nil {
return merrors.InternalServerError(s.id, "could not assign role to account: %v", err.Error())
}
if err = s.indexAccount(acc.Id); err != nil {
return merrors.InternalServerError(s.id, "could not index new account: %v", err.Error())
}
s.log.Debug().Interface("account", acc).Msg("account after indexing")
if acc.PasswordProfile != nil {
@@ -382,6 +347,17 @@ func (s Service) CreateAccount(ctx context.Context, in *proto.CreateAccountReque
out.OnPremisesSamAccountName = acc.OnPremisesSamAccountName
}
// TODO: assign user role to all new users for now, as create Account request does not have any role field
if s.RoleService == nil {
return merrors.InternalServerError(s.id, "could not assign role to account: roleService not configured")
}
if _, err = s.RoleService.AssignRoleToUser(ctx, &settings.AssignRoleToUserRequest{
AccountUuid: acc.Id,
RoleId: settings_svc.BundleUUIDRoleUser,
}); err != nil {
return merrors.InternalServerError(s.id, "could not assign role to account: %v", err.Error())
}
return
}

View File

@@ -17,28 +17,6 @@ import (
"github.com/owncloud/ocis-accounts/pkg/provider"
)
func (s Service) indexGroups(path string) (err error) {
var f *os.File
if f, err = os.Open(path); err != nil {
s.log.Error().Err(err).Str("dir", path).Msg("could not open groups folder")
return
}
list, err := f.Readdir(-1)
f.Close()
if err != nil {
s.log.Error().Err(err).Str("dir", path).Msg("could not list groups folder")
return
}
for _, file := range list {
err = s.indexGroup(file.Name())
if err != nil {
s.log.Error().Err(err).Str("file", file.Name()).Msg("could not index account")
}
}
return
}
// accLock mutually exclude readers from writers on group files
var groupLock sync.Mutex

View File

@@ -28,28 +28,28 @@ func newOptions(opts ...Option) Options {
return opt
}
// Logger provides a function to set the logger option.
// Logger provides a function to set the Logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Config provides a function to set the config option.
// Config provides a function to set the Config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
// RoleService provides a function to set the role service option.
// RoleService provides a function to set the RoleService option.
func RoleService(val settings.RoleService) Option {
return func(o *Options) {
o.RoleService = val
}
}
// RoleManager provides a function to set the roles manager option.
// RoleManager provides a function to set the RoleManager option.
func RoleManager(val *roles.Manager) Option {
return func(o *Options) {
o.RoleManager = val

View File

@@ -9,6 +9,7 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/blevesearch/bleve"
"github.com/blevesearch/bleve/analysis/analyzer/custom"
@@ -17,6 +18,7 @@ import (
"github.com/blevesearch/bleve/analysis/analyzer/standard"
"github.com/blevesearch/bleve/analysis/token/lowercase"
"github.com/blevesearch/bleve/analysis/tokenizer/unicode"
mclient "github.com/micro/go-micro/v2/client"
"github.com/owncloud/ocis-accounts/pkg/config"
"github.com/owncloud/ocis-accounts/pkg/proto/v0"
"github.com/owncloud/ocis-pkg/v2/log"
@@ -30,228 +32,55 @@ func New(opts ...Option) (s *Service, err error) {
options := newOptions(opts...)
logger := options.Logger
cfg := options.Config
roleService := options.RoleService
if roleService == nil {
// https://github.com/owncloud/ocis-proxy/issues/38
// TODO this won't work with a registry other than mdns. Look into Micro's client initialization.
roleService = settings.NewRoleService("com.owncloud.api.settings", mclient.DefaultClient)
}
roleManager := options.RoleManager
// read all user and group records
if roleManager == nil {
m := roles.NewManager(
roles.CacheSize(1024),
roles.CacheTTL(time.Hour*24*7),
roles.Logger(options.Logger),
roles.RoleService(roleService),
)
roleManager = &m
}
s = &Service{
id: cfg.GRPC.Namespace + "." + cfg.Server.Name,
log: logger,
Config: cfg,
RoleService: roleService,
RoleManager: roleManager,
}
// build an index
if s.index, err = s.buildIndex(); err != nil {
return nil, err
}
// create default accounts
accountsDir := filepath.Join(cfg.Server.AccountsDataPath, "accounts")
{
// check if accounts exist
var fi os.FileInfo
if fi, err = os.Stat(accountsDir); err != nil {
if os.IsNotExist(err) {
// create accounts directory
if err = os.MkdirAll(accountsDir, 0700); err != nil {
return nil, err
}
// create default accounts
accounts := []proto.Account{
{
Id: "4c510ada-c86b-4815-8820-42cdf82c3d51",
PreferredName: "einstein",
OnPremisesSamAccountName: "einstein",
Mail: "einstein@example.org",
DisplayName: "Albert Einstein",
UidNumber: 20000,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=35210$sa1u5Pmfo4cr23Vw$RJNGElaDB1D3xorWkfTEGm2Ko.o2QL3E0cimKx23MNxVWVFSkUUeRoC7FqC4RzYDNQBD6cKzovTEaDD.8TDkD.",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
{Id: "6040aa17-9c64-4fef-9bd0-77234d71bad0"}, // sailing-lovers
{Id: "dd58e5ec-842e-498b-8800-61f2ec6f911f"}, // violin-haters
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e"}, // physics-lovers
},
},
{
Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
PreferredName: "marie",
OnPremisesSamAccountName: "marie",
Mail: "marie@example.org",
DisplayName: "Marie Curie",
UidNumber: 20001,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=81434$sa1u5Pmfo4cr23Vw$W78cyL884GmuvDpxYPvSRBVzEj02T5QhTTcI8Dv4IKvMooDFGv4bwaWMkH9HfJ0wgpEBW7Lp.4Cad0xE/MYSg1",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
{Id: "7b87fd49-286e-4a5f-bafd-c535d5dd997a"}, // radium-lovers
{Id: "cedc21aa-4072-4614-8676-fa9165f598ff"}, // polonium-lovers
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e"}, // physics-lovers
},
},
{
Id: "932b4540-8d16-481e-8ef4-588e4b6b151c",
PreferredName: "richard",
OnPremisesSamAccountName: "richard",
Mail: "richard@example.org",
DisplayName: "Richard Feynman",
UidNumber: 20002,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=5524$sa1u5Pmfo4cr23Vw$58bQVL/JeUlwM0RY21YKAFMvKvwKLLysGllYXox.vwKT5dHMwdzJjCxwTDMnB2o2pwexC8o/iOXyP2zrhALS40",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
{Id: "a1726108-01f8-4c30-88df-2b1a9d1cba1a"}, // quantum-lovers
{Id: "167cbee2-0518-455a-bfb2-031fe0621e5d"}, // philosophy-haters
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e"}, // physics-lovers
},
},
// admin user(s)
{
Id: "058bff95-6708-4fe5-91e4-9ea3d377588b",
PreferredName: "moss",
OnPremisesSamAccountName: "moss",
Mail: "moss@example.org",
DisplayName: "Maurice Moss",
UidNumber: 20003,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=47068$lhw6odzXW0LTk/ao$GgxS.pIgP8jawLJBAiyNor2FrWzrULF95PwspRkli2W3VF.4HEwTYlQfRXbNQBMjNCEcEYlgZo3a.kRz2k2N0/",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
},
},
// technical users for kopano and reva
{
Id: "820ba2a1-3f54-4538-80a4-2d73007e30bf",
PreferredName: "konnectd",
OnPremisesSamAccountName: "konnectd",
Mail: "idp@example.org",
DisplayName: "Kopano Konnectd",
UidNumber: 10000,
GidNumber: 15000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=9746$sa1u5Pmfo4cr23Vw$2hnwpkTvUkWX0v6mh8Aw1pbzEXa9EUJzmrey4g2W/8arwWCwhteqU//3aWnA3S0d5T21fOKYteoqlsN1IbTcN.",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "34f38767-c937-4eb6-b847-1c175829a2a0"}, // sysusers
},
},
{
Id: "bc596f3c-c955-4328-80a0-60d018b4ad57",
PreferredName: "reva",
OnPremisesSamAccountName: "reva",
Mail: "storage@example.org",
DisplayName: "Reva Inter Operability Platform",
UidNumber: 10001,
GidNumber: 15000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=91087$sa1u5Pmfo4cr23Vw$wPC3BbMTbP/ytlo0p.f99zJifyO70AUCdKIK9hkhwutBKGCirLmZs/MsWAG6xHjVvmnmHN5NoON7FUGv5pPaN.",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "34f38767-c937-4eb6-b847-1c175829a2a0"}, // sysusers
},
},
}
for i := range accounts {
// create account on disk
var bytes []byte
if bytes, err = json.Marshal(&accounts[i]); err != nil {
logger.Error().Err(err).Interface("account", &accounts[i]).Msg("could not marshal default account")
return
}
path := filepath.Join(accountsDir, accounts[i].Id)
if err = ioutil.WriteFile(path, bytes, 0600); err != nil {
accounts[i].PasswordProfile.Password = "***REMOVED***"
logger.Error().Err(err).Str("path", path).Interface("account", &accounts[i]).Msg("could not persist default account")
return
}
}
// set role for admin users and regular users
assignRoleToUser("058bff95-6708-4fe5-91e4-9ea3d377588b", settings_svc.BundleUUIDRoleAdmin, roleService, logger)
for _, accountID := range []string{
"058bff95-6708-4fe5-91e4-9ea3d377588b", //moss
} {
assignRoleToUser(accountID, settings_svc.BundleUUIDRoleAdmin, roleService, logger)
}
for _, accountID := range []string{
"4c510ada-c86b-4815-8820-42cdf82c3d51", //einstein
"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c", //marie
"932b4540-8d16-481e-8ef4-588e4b6b151c", //richard
} {
assignRoleToUser(accountID, settings_svc.BundleUUIDRoleUser, roleService, logger)
}
}
} else if !fi.IsDir() {
return nil, fmt.Errorf("%s is not a directory", accountsDir)
}
if err = s.createDefaultAccounts(accountsDir); err != nil {
return nil, err
}
// create default groups
groupsDir := filepath.Join(cfg.Server.AccountsDataPath, "groups")
{
// check if groups exist
var fi os.FileInfo
if fi, err = os.Stat(groupsDir); err != nil {
if os.IsNotExist(err) {
// create accounts directory
if err = os.MkdirAll(groupsDir, 0700); err != nil {
return nil, err
}
// create default accounts
groups := []proto.Group{
{Id: "34f38767-c937-4eb6-b847-1c175829a2a0", GidNumber: 15000, OnPremisesSamAccountName: "sysusers", DisplayName: "Technical users", Description: "A group for technical users. They should not show up in sharing dialogs.", Members: []*proto.Account{
{Id: "820ba2a1-3f54-4538-80a4-2d73007e30bf"}, // konnectd
{Id: "bc596f3c-c955-4328-80a0-60d018b4ad57"}, // reva
}},
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa", GidNumber: 30000, OnPremisesSamAccountName: "users", DisplayName: "Users", Description: "A group every normal user belongs to.", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
{Id: "6040aa17-9c64-4fef-9bd0-77234d71bad0", GidNumber: 30001, OnPremisesSamAccountName: "sailing-lovers", DisplayName: "Sailing lovers", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
}},
{Id: "dd58e5ec-842e-498b-8800-61f2ec6f911f", GidNumber: 30002, OnPremisesSamAccountName: "violin-haters", DisplayName: "Violin haters", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
}},
{Id: "7b87fd49-286e-4a5f-bafd-c535d5dd997a", GidNumber: 30003, OnPremisesSamAccountName: "radium-lovers", DisplayName: "Radium lovers", Members: []*proto.Account{
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
}},
{Id: "cedc21aa-4072-4614-8676-fa9165f598ff", GidNumber: 30004, OnPremisesSamAccountName: "polonium-lovers", DisplayName: "Polonium lovers", Members: []*proto.Account{
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
}},
{Id: "a1726108-01f8-4c30-88df-2b1a9d1cba1a", GidNumber: 30005, OnPremisesSamAccountName: "quantum-lovers", DisplayName: "Quantum lovers", Members: []*proto.Account{
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
{Id: "167cbee2-0518-455a-bfb2-031fe0621e5d", GidNumber: 30006, OnPremisesSamAccountName: "philosophy-haters", DisplayName: "Philosophy haters", Members: []*proto.Account{
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e", GidNumber: 30007, OnPremisesSamAccountName: "physics-lovers", DisplayName: "Physics lovers", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
}
for i := range groups {
var bytes []byte
if bytes, err = json.Marshal(&groups[i]); err != nil {
logger.Error().Err(err).Interface("group", &groups[i]).Msg("could not marshal default group")
return
}
path := filepath.Join(groupsDir, groups[i].Id)
if err = ioutil.WriteFile(path, bytes, 0600); err != nil {
logger.Error().Err(err).Str("path", path).Interface("group", &groups[i]).Msg("could not persist default group")
return
}
}
}
} else if !fi.IsDir() {
return nil, fmt.Errorf("%s is not a directory", groupsDir)
}
if err = s.createDefaultGroups(groupsDir); err != nil {
return nil, err
}
// TODO watch folders for new records
return
}
func (s Service) buildIndex() (index bleve.Index, err error) {
indexMapping := bleve.NewIndexMapping()
// keep all symbols in terms to allow exact maching, eg. emails
indexMapping.DefaultAnalyzer = keyword.Name
@@ -282,7 +111,7 @@ func New(opts ...Option) (s *Service, err error) {
},
})
if err != nil {
return nil, err
return
}
lowercaseTextFieldMapping := bleve.NewTextFieldMapping()
lowercaseTextFieldMapping.Analyzer = "lowercase"
@@ -321,34 +150,244 @@ func New(opts ...Option) (s *Service, err error) {
// documents in the index by querying for that property.
indexMapping.TypeField = "BleveType"
s = &Service{
id: cfg.GRPC.Namespace + "." + cfg.Server.Name,
log: logger,
Config: cfg,
RoleService: roleService,
RoleManager: roleManager,
}
indexDir := filepath.Join(cfg.Server.AccountsDataPath, "index.bleve")
indexDir := filepath.Join(s.Config.Server.AccountsDataPath, "index.bleve")
// for now recreate index on every start
if err = os.RemoveAll(indexDir); err != nil {
return nil, err
}
if s.index, err = bleve.New(indexDir, indexMapping); err != nil {
return
}
if err = s.indexAccounts(accountsDir); err != nil {
if index, err = bleve.New(indexDir, indexMapping); err != nil {
return nil, err
}
if err = s.indexGroups(groupsDir); err != nil {
return nil, err
}
// TODO watch folders for new records
return
}
func (s Service) createDefaultAccounts(accountsDir string) (err error) {
// check if accounts exist
var fi os.FileInfo
if fi, err = os.Stat(accountsDir); err != nil {
if os.IsNotExist(err) {
// create accounts directory
if err = os.MkdirAll(accountsDir, 0700); err != nil {
return
}
// create default accounts
accounts := []proto.Account{
{
Id: "4c510ada-c86b-4815-8820-42cdf82c3d51",
PreferredName: "einstein",
OnPremisesSamAccountName: "einstein",
Mail: "einstein@example.org",
DisplayName: "Albert Einstein",
UidNumber: 20000,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=35210$sa1u5Pmfo4cr23Vw$RJNGElaDB1D3xorWkfTEGm2Ko.o2QL3E0cimKx23MNxVWVFSkUUeRoC7FqC4RzYDNQBD6cKzovTEaDD.8TDkD.",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
{Id: "6040aa17-9c64-4fef-9bd0-77234d71bad0"}, // sailing-lovers
{Id: "dd58e5ec-842e-498b-8800-61f2ec6f911f"}, // violin-haters
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e"}, // physics-lovers
},
},
{
Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
PreferredName: "marie",
OnPremisesSamAccountName: "marie",
Mail: "marie@example.org",
DisplayName: "Marie Curie",
UidNumber: 20001,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=81434$sa1u5Pmfo4cr23Vw$W78cyL884GmuvDpxYPvSRBVzEj02T5QhTTcI8Dv4IKvMooDFGv4bwaWMkH9HfJ0wgpEBW7Lp.4Cad0xE/MYSg1",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
{Id: "7b87fd49-286e-4a5f-bafd-c535d5dd997a"}, // radium-lovers
{Id: "cedc21aa-4072-4614-8676-fa9165f598ff"}, // polonium-lovers
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e"}, // physics-lovers
},
},
{
Id: "932b4540-8d16-481e-8ef4-588e4b6b151c",
PreferredName: "richard",
OnPremisesSamAccountName: "richard",
Mail: "richard@example.org",
DisplayName: "Richard Feynman",
UidNumber: 20002,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=5524$sa1u5Pmfo4cr23Vw$58bQVL/JeUlwM0RY21YKAFMvKvwKLLysGllYXox.vwKT5dHMwdzJjCxwTDMnB2o2pwexC8o/iOXyP2zrhALS40",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
{Id: "a1726108-01f8-4c30-88df-2b1a9d1cba1a"}, // quantum-lovers
{Id: "167cbee2-0518-455a-bfb2-031fe0621e5d"}, // philosophy-haters
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e"}, // physics-lovers
},
},
// admin user(s)
{
Id: "058bff95-6708-4fe5-91e4-9ea3d377588b",
PreferredName: "moss",
OnPremisesSamAccountName: "moss",
Mail: "moss@example.org",
DisplayName: "Maurice Moss",
UidNumber: 20003,
GidNumber: 30000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=47068$lhw6odzXW0LTk/ao$GgxS.pIgP8jawLJBAiyNor2FrWzrULF95PwspRkli2W3VF.4HEwTYlQfRXbNQBMjNCEcEYlgZo3a.kRz2k2N0/",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
},
},
// technical users for kopano and reva
{
Id: "820ba2a1-3f54-4538-80a4-2d73007e30bf",
PreferredName: "konnectd",
OnPremisesSamAccountName: "konnectd",
Mail: "idp@example.org",
DisplayName: "Kopano Konnectd",
UidNumber: 10000,
GidNumber: 15000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=9746$sa1u5Pmfo4cr23Vw$2hnwpkTvUkWX0v6mh8Aw1pbzEXa9EUJzmrey4g2W/8arwWCwhteqU//3aWnA3S0d5T21fOKYteoqlsN1IbTcN.",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "34f38767-c937-4eb6-b847-1c175829a2a0"}, // sysusers
},
},
{
Id: "bc596f3c-c955-4328-80a0-60d018b4ad57",
PreferredName: "reva",
OnPremisesSamAccountName: "reva",
Mail: "storage@example.org",
DisplayName: "Reva Inter Operability Platform",
UidNumber: 10001,
GidNumber: 15000,
PasswordProfile: &proto.PasswordProfile{
Password: "$6$rounds=91087$sa1u5Pmfo4cr23Vw$wPC3BbMTbP/ytlo0p.f99zJifyO70AUCdKIK9hkhwutBKGCirLmZs/MsWAG6xHjVvmnmHN5NoON7FUGv5pPaN.",
},
AccountEnabled: true,
MemberOf: []*proto.Group{
{Id: "34f38767-c937-4eb6-b847-1c175829a2a0"}, // sysusers
},
},
}
for i := range accounts {
// create account on disk
var bytes []byte
if bytes, err = json.Marshal(&accounts[i]); err != nil {
s.log.Error().Err(err).Interface("account", &accounts[i]).Msg("could not marshal default account")
return
}
path := filepath.Join(accountsDir, accounts[i].Id)
if err = ioutil.WriteFile(path, bytes, 0600); err != nil {
accounts[i].PasswordProfile.Password = "***REMOVED***"
s.log.Error().Err(err).Str("path", path).Interface("account", &accounts[i]).Msg("could not persist default account")
return
}
if err = s.indexAccount(accounts[i].Id); err != nil {
accounts[i].PasswordProfile.Password = "***REMOVED***"
s.log.Error().Err(err).Str("path", path).Interface("account", &accounts[i]).Msg("could not index default account")
return
}
}
// set role for admin users and regular users
assignRoleToUser("058bff95-6708-4fe5-91e4-9ea3d377588b", settings_svc.BundleUUIDRoleAdmin, s.RoleService, s.log)
for _, accountID := range []string{
"058bff95-6708-4fe5-91e4-9ea3d377588b", //moss
} {
assignRoleToUser(accountID, settings_svc.BundleUUIDRoleAdmin, s.RoleService, s.log)
}
for _, accountID := range []string{
"4c510ada-c86b-4815-8820-42cdf82c3d51", //einstein
"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c", //marie
"932b4540-8d16-481e-8ef4-588e4b6b151c", //richard
} {
assignRoleToUser(accountID, settings_svc.BundleUUIDRoleUser, s.RoleService, s.log)
}
}
} else if !fi.IsDir() {
return fmt.Errorf("%s is not a directory", accountsDir)
}
return nil
}
func (s Service) createDefaultGroups(groupsDir string) (err error) {
// check if groups exist
var fi os.FileInfo
if fi, err = os.Stat(groupsDir); err != nil {
if os.IsNotExist(err) {
// create accounts directory
if err = os.MkdirAll(groupsDir, 0700); err != nil {
return
}
// create default accounts
groups := []proto.Group{
{Id: "34f38767-c937-4eb6-b847-1c175829a2a0", GidNumber: 15000, OnPremisesSamAccountName: "sysusers", DisplayName: "Technical users", Description: "A group for technical users. They should not show up in sharing dialogs.", Members: []*proto.Account{
{Id: "820ba2a1-3f54-4538-80a4-2d73007e30bf"}, // konnectd
{Id: "bc596f3c-c955-4328-80a0-60d018b4ad57"}, // reva
}},
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa", GidNumber: 30000, OnPremisesSamAccountName: "users", DisplayName: "Users", Description: "A group every normal user belongs to.", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
{Id: "6040aa17-9c64-4fef-9bd0-77234d71bad0", GidNumber: 30001, OnPremisesSamAccountName: "sailing-lovers", DisplayName: "Sailing lovers", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
}},
{Id: "dd58e5ec-842e-498b-8800-61f2ec6f911f", GidNumber: 30002, OnPremisesSamAccountName: "violin-haters", DisplayName: "Violin haters", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
}},
{Id: "7b87fd49-286e-4a5f-bafd-c535d5dd997a", GidNumber: 30003, OnPremisesSamAccountName: "radium-lovers", DisplayName: "Radium lovers", Members: []*proto.Account{
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
}},
{Id: "cedc21aa-4072-4614-8676-fa9165f598ff", GidNumber: 30004, OnPremisesSamAccountName: "polonium-lovers", DisplayName: "Polonium lovers", Members: []*proto.Account{
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
}},
{Id: "a1726108-01f8-4c30-88df-2b1a9d1cba1a", GidNumber: 30005, OnPremisesSamAccountName: "quantum-lovers", DisplayName: "Quantum lovers", Members: []*proto.Account{
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
{Id: "167cbee2-0518-455a-bfb2-031fe0621e5d", GidNumber: 30006, OnPremisesSamAccountName: "philosophy-haters", DisplayName: "Philosophy haters", Members: []*proto.Account{
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
{Id: "262982c1-2362-4afa-bfdf-8cbfef64a06e", GidNumber: 30007, OnPremisesSamAccountName: "physics-lovers", DisplayName: "Physics lovers", Members: []*proto.Account{
{Id: "4c510ada-c86b-4815-8820-42cdf82c3d51"}, // einstein
{Id: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}, // marie
{Id: "932b4540-8d16-481e-8ef4-588e4b6b151c"}, // feynman
}},
}
for i := range groups {
var bytes []byte
if bytes, err = json.Marshal(&groups[i]); err != nil {
s.log.Error().Err(err).Interface("group", &groups[i]).Msg("could not marshal default group")
return
}
path := filepath.Join(groupsDir, groups[i].Id)
if err = ioutil.WriteFile(path, bytes, 0600); err != nil {
s.log.Error().Err(err).Str("path", path).Interface("group", &groups[i]).Msg("could not persist default group")
return
}
if err = s.indexGroup(groups[i].Id); err != nil {
s.log.Error().Err(err).Str("path", path).Interface("group", &groups[i]).Msg("could not index default group")
return
}
}
}
} else if !fi.IsDir() {
return fmt.Errorf("%s is not a directory", groupsDir)
}
return nil
}
func assignRoleToUser(accountID, roleID string, rs settings.RoleService, logger log.Logger) (ok bool) {
_, err := rs.AssignRoleToUser(context.Background(), &settings.AssignRoleToUserRequest{
AccountUuid: accountID,