github.com/cs3org/reva/v2@v2.27.7/pkg/user/manager/owncloudsql/owncloudsql.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package owncloudsql 20 21 import ( 22 "context" 23 "database/sql" 24 "fmt" 25 26 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 27 "github.com/cs3org/reva/v2/pkg/appctx" 28 "github.com/cs3org/reva/v2/pkg/errtypes" 29 "github.com/cs3org/reva/v2/pkg/user" 30 "github.com/cs3org/reva/v2/pkg/user/manager/owncloudsql/accounts" 31 "github.com/cs3org/reva/v2/pkg/user/manager/registry" 32 "github.com/mitchellh/mapstructure" 33 "github.com/pkg/errors" 34 35 // Provides mysql drivers 36 _ "github.com/go-sql-driver/mysql" 37 ) 38 39 func init() { 40 registry.Register("owncloudsql", NewMysql) 41 } 42 43 type manager struct { 44 c *config 45 db *accounts.Accounts 46 } 47 48 type config struct { 49 DbUsername string `mapstructure:"dbusername"` 50 DbPassword string `mapstructure:"dbpassword"` 51 DbHost string `mapstructure:"dbhost"` 52 DbPort int `mapstructure:"dbport"` 53 DbName string `mapstructure:"dbname"` 54 Idp string `mapstructure:"idp"` 55 Nobody int64 `mapstructure:"nobody"` 56 JoinUsername bool `mapstructure:"join_username"` 57 JoinOwnCloudUUID bool `mapstructure:"join_ownclouduuid"` 58 EnableMedialSearch bool `mapstructure:"enable_medial_search"` 59 } 60 61 // NewMysql returns a new user manager connection to an owncloud mysql database 62 func NewMysql(m map[string]interface{}) (user.Manager, error) { 63 mgr := &manager{} 64 err := mgr.Configure(m) 65 if err != nil { 66 err = errors.Wrap(err, "error creating a new manager") 67 return nil, err 68 } 69 70 mgr.db, err = accounts.NewMysql( 71 fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", mgr.c.DbUsername, mgr.c.DbPassword, mgr.c.DbHost, mgr.c.DbPort, mgr.c.DbName), 72 mgr.c.JoinUsername, 73 mgr.c.JoinOwnCloudUUID, 74 mgr.c.EnableMedialSearch, 75 ) 76 if err != nil { 77 return nil, err 78 } 79 80 return mgr, nil 81 } 82 83 func (m *manager) Configure(ml map[string]interface{}) error { 84 c, err := parseConfig(ml) 85 if err != nil { 86 return err 87 } 88 89 if c.Nobody == 0 { 90 c.Nobody = 99 91 } 92 93 m.c = c 94 return nil 95 } 96 97 func parseConfig(m map[string]interface{}) (*config, error) { 98 c := &config{} 99 if err := mapstructure.Decode(m, &c); err != nil { 100 return nil, err 101 } 102 return c, nil 103 } 104 105 func (m *manager) GetUser(ctx context.Context, uid *userpb.UserId, skipFetchingGroups bool) (*userpb.User, error) { 106 // search via the user_id 107 a, err := m.db.GetAccountByClaim(ctx, "userid", uid.OpaqueId) 108 if err == sql.ErrNoRows { 109 return nil, errtypes.NotFound(uid.OpaqueId) 110 } 111 return m.convertToCS3User(ctx, a, skipFetchingGroups) 112 } 113 114 func (m *manager) GetUserByClaim(ctx context.Context, claim, value string, skipFetchingGroups bool) (*userpb.User, error) { 115 a, err := m.db.GetAccountByClaim(ctx, claim, value) 116 if err == sql.ErrNoRows { 117 return nil, errtypes.NotFound(claim + "=" + value) 118 } else if err != nil { 119 return nil, err 120 } 121 return m.convertToCS3User(ctx, a, skipFetchingGroups) 122 } 123 124 func (m *manager) FindUsers(ctx context.Context, query string, skipFetchingGroups bool) ([]*userpb.User, error) { 125 126 accounts, err := m.db.FindAccounts(ctx, query) 127 if err == sql.ErrNoRows { 128 return nil, errtypes.NotFound("no users found for " + query) 129 } else if err != nil { 130 return nil, err 131 } 132 133 users := make([]*userpb.User, 0, len(accounts)) 134 for i := range accounts { 135 u, err := m.convertToCS3User(ctx, &accounts[i], skipFetchingGroups) 136 if err != nil { 137 appctx.GetLogger(ctx).Error().Err(err).Interface("account", accounts[i]).Msg("could not convert account, skipping") 138 continue 139 } 140 users = append(users, u) 141 } 142 143 return users, nil 144 } 145 146 func (m *manager) GetUserGroups(ctx context.Context, uid *userpb.UserId) ([]string, error) { 147 groups, err := m.db.GetAccountGroups(ctx, uid.OpaqueId) 148 if err == sql.ErrNoRows { 149 return nil, errtypes.NotFound("no groups found for uid " + uid.OpaqueId) 150 } else if err != nil { 151 return nil, err 152 } 153 return groups, nil 154 } 155 156 func (m *manager) convertToCS3User(ctx context.Context, a *accounts.Account, skipFetchingGroups bool) (*userpb.User, error) { 157 u := &userpb.User{ 158 Id: &userpb.UserId{ 159 Idp: m.c.Idp, 160 OpaqueId: a.OwnCloudUUID.String, 161 Type: userpb.UserType_USER_TYPE_PRIMARY, 162 }, 163 Username: a.Username.String, 164 Mail: a.Email.String, 165 DisplayName: a.DisplayName.String, 166 //Groups: groups, 167 GidNumber: m.c.Nobody, 168 UidNumber: m.c.Nobody, 169 } 170 // https://github.com/cs3org/reva/pull/4135 171 // fall back to userid 172 if u.Id.OpaqueId == "" { 173 u.Id.OpaqueId = a.UserID 174 } 175 if u.Username == "" { 176 u.Username = u.Id.OpaqueId 177 } 178 if u.DisplayName == "" { 179 u.DisplayName = u.Id.OpaqueId 180 } 181 182 if !skipFetchingGroups { 183 var err error 184 if u.Groups, err = m.GetUserGroups(ctx, u.Id); err != nil { 185 return nil, err 186 } 187 } 188 return u, nil 189 }