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  }