github.com/cs3org/reva/v2@v2.27.7/pkg/user/manager/json/json.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 json
    20  
    21  import (
    22  	"context"
    23  	"encoding/json"
    24  	"os"
    25  	"strconv"
    26  	"strings"
    27  
    28  	"github.com/cs3org/reva/v2/pkg/user"
    29  	"github.com/cs3org/reva/v2/pkg/user/manager/registry"
    30  	"github.com/mitchellh/mapstructure"
    31  	"github.com/pkg/errors"
    32  	"google.golang.org/protobuf/proto"
    33  
    34  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    35  	"github.com/cs3org/reva/v2/pkg/errtypes"
    36  )
    37  
    38  func init() {
    39  	registry.Register("json", New)
    40  }
    41  
    42  type manager struct {
    43  	users []*userpb.User
    44  }
    45  
    46  type config struct {
    47  	// Users holds a path to a file containing json conforming to the Users struct
    48  	Users string `mapstructure:"users"`
    49  }
    50  
    51  func (c *config) init() {
    52  	if c.Users == "" {
    53  		c.Users = "/etc/revad/users.json"
    54  	}
    55  }
    56  
    57  func parseConfig(m map[string]interface{}) (*config, error) {
    58  	c := &config{}
    59  	if err := mapstructure.Decode(m, c); err != nil {
    60  		err = errors.Wrap(err, "error decoding conf")
    61  		return nil, err
    62  	}
    63  	c.init()
    64  	return c, nil
    65  }
    66  
    67  // New returns a user manager implementation that reads a json file to provide user metadata.
    68  func New(m map[string]interface{}) (user.Manager, error) {
    69  	mgr := &manager{}
    70  	err := mgr.Configure(m)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	return mgr, nil
    75  }
    76  
    77  func (m *manager) Configure(ml map[string]interface{}) error {
    78  	c, err := parseConfig(ml)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	f, err := os.ReadFile(c.Users)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	users := []*userpb.User{}
    89  
    90  	err = json.Unmarshal(f, &users)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	m.users = users
    95  	return nil
    96  }
    97  
    98  func (m *manager) GetUser(ctx context.Context, uid *userpb.UserId, skipFetchingGroups bool) (*userpb.User, error) {
    99  	for _, u := range m.users {
   100  		if (u.Id.GetOpaqueId() == uid.OpaqueId || u.Username == uid.OpaqueId) && (uid.Idp == "" || uid.Idp == u.Id.GetIdp()) {
   101  			user := proto.Clone(u).(*userpb.User)
   102  			if skipFetchingGroups {
   103  				user.Groups = nil
   104  			}
   105  			return user, nil
   106  		}
   107  	}
   108  	return nil, errtypes.NotFound(uid.OpaqueId)
   109  }
   110  
   111  func (m *manager) GetUserByClaim(ctx context.Context, claim, value string, skipFetchingGroups bool) (*userpb.User, error) {
   112  	for _, u := range m.users {
   113  		if userClaim, err := extractClaim(u, claim); err == nil && value == userClaim {
   114  			user := proto.Clone(u).(*userpb.User)
   115  			if skipFetchingGroups {
   116  				user.Groups = nil
   117  			}
   118  			return user, nil
   119  		}
   120  	}
   121  	return nil, errtypes.NotFound(value)
   122  }
   123  
   124  func extractClaim(u *userpb.User, claim string) (string, error) {
   125  	switch claim {
   126  	case "mail":
   127  		return u.Mail, nil
   128  	case "username":
   129  		return u.Username, nil
   130  	case "userid":
   131  		return u.Id.OpaqueId, nil
   132  	case "uid":
   133  		if u.UidNumber != 0 {
   134  			return strconv.FormatInt(u.UidNumber, 10), nil
   135  		}
   136  	}
   137  	return "", errors.New("json: invalid field")
   138  }
   139  
   140  // TODO(jfd) search Opaque? compare sub?
   141  func userContains(u *userpb.User, query string) bool {
   142  	query = strings.ToLower(query)
   143  	return strings.Contains(strings.ToLower(u.Username), query) || strings.Contains(strings.ToLower(u.DisplayName), query) ||
   144  		strings.Contains(strings.ToLower(u.Mail), query) || strings.Contains(strings.ToLower(u.Id.OpaqueId), query)
   145  }
   146  
   147  func (m *manager) FindUsers(ctx context.Context, query string, skipFetchingGroups bool) ([]*userpb.User, error) {
   148  	users := []*userpb.User{}
   149  	for _, u := range m.users {
   150  		if userContains(u, query) {
   151  			user := proto.Clone(u).(*userpb.User)
   152  			if skipFetchingGroups {
   153  				user.Groups = nil
   154  			}
   155  			users = append(users, user)
   156  		}
   157  	}
   158  	return users, nil
   159  }
   160  
   161  func (m *manager) GetUserGroups(ctx context.Context, uid *userpb.UserId) ([]string, error) {
   162  	user, err := m.GetUser(ctx, uid, false)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	return user.Groups, nil
   167  }