github.com/cs3org/reva/v2@v2.27.7/pkg/group/manager/json/json.go (about)

     1  // Copyright 2018-2020 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  	grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
    29  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    30  	"github.com/cs3org/reva/v2/pkg/errtypes"
    31  	"github.com/cs3org/reva/v2/pkg/group"
    32  	"github.com/cs3org/reva/v2/pkg/group/manager/registry"
    33  	"github.com/mitchellh/mapstructure"
    34  	"github.com/pkg/errors"
    35  	"google.golang.org/protobuf/proto"
    36  )
    37  
    38  func init() {
    39  	registry.Register("json", New)
    40  }
    41  
    42  type manager struct {
    43  	groups []*grouppb.Group
    44  }
    45  
    46  type config struct {
    47  	// Groups holds a path to a file containing json conforming to the Groups struct
    48  	Groups string `mapstructure:"groups"`
    49  }
    50  
    51  func (c *config) init() {
    52  	if c.Groups == "" {
    53  		c.Groups = "/etc/revad/groups.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 group manager implementation that reads a json file to provide group metadata.
    68  func New(m map[string]interface{}) (group.Manager, error) {
    69  	c, err := parseConfig(m)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	f, err := os.ReadFile(c.Groups)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	groups := []*grouppb.Group{}
    80  
    81  	err = json.Unmarshal(f, &groups)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	return &manager{
    87  		groups: groups,
    88  	}, nil
    89  }
    90  
    91  func (m *manager) GetGroup(ctx context.Context, gid *grouppb.GroupId, skipFetchingMembers bool) (*grouppb.Group, error) {
    92  	for _, g := range m.groups {
    93  		if (g.Id.GetOpaqueId() == gid.OpaqueId || g.GroupName == gid.OpaqueId) && (gid.Idp == "" || gid.Idp == g.Id.GetIdp()) {
    94  			group := proto.Clone(g).(*grouppb.Group)
    95  			if skipFetchingMembers {
    96  				group.Members = nil
    97  			}
    98  			return group, nil
    99  		}
   100  	}
   101  	return nil, errtypes.NotFound(gid.OpaqueId)
   102  }
   103  
   104  func (m *manager) GetGroupByClaim(ctx context.Context, claim, value string, skipFetchingMembers bool) (*grouppb.Group, error) {
   105  	for _, g := range m.groups {
   106  		if groupClaim, err := extractClaim(g, claim); err == nil && value == groupClaim {
   107  			group := proto.Clone(g).(*grouppb.Group)
   108  			if skipFetchingMembers {
   109  				group.Members = nil
   110  			}
   111  			return group, nil
   112  		}
   113  	}
   114  	return nil, errtypes.NotFound(value)
   115  }
   116  
   117  func extractClaim(g *grouppb.Group, claim string) (string, error) {
   118  	switch claim {
   119  	case "group_name":
   120  		return g.GroupName, nil
   121  	case "gid_number":
   122  		return strconv.FormatInt(g.GidNumber, 10), nil
   123  	case "display_name":
   124  		return g.DisplayName, nil
   125  	case "mail":
   126  		return g.Mail, nil
   127  	}
   128  	return "", errors.New("json: invalid field")
   129  }
   130  
   131  func (m *manager) FindGroups(ctx context.Context, query string, skipFetchingMembers bool) ([]*grouppb.Group, error) {
   132  	groups := []*grouppb.Group{}
   133  	for _, g := range m.groups {
   134  		if groupContains(g, query) {
   135  			group := proto.Clone(g).(*grouppb.Group)
   136  			if skipFetchingMembers {
   137  				group.Members = nil
   138  			}
   139  			groups = append(groups, group)
   140  		}
   141  	}
   142  	return groups, nil
   143  }
   144  
   145  func groupContains(g *grouppb.Group, query string) bool {
   146  	query = strings.ToLower(query)
   147  	return strings.Contains(strings.ToLower(g.GroupName), query) || strings.Contains(strings.ToLower(g.DisplayName), query) ||
   148  		strings.Contains(strings.ToLower(g.Mail), query) || strings.Contains(strings.ToLower(g.Id.OpaqueId), query)
   149  }
   150  
   151  func (m *manager) GetMembers(ctx context.Context, gid *grouppb.GroupId) ([]*userpb.UserId, error) {
   152  	for _, g := range m.groups {
   153  		if g.Id.GetOpaqueId() == gid.OpaqueId || g.GroupName == gid.OpaqueId {
   154  			return g.Members, nil
   155  		}
   156  	}
   157  	return nil, errtypes.NotFound(gid.OpaqueId)
   158  }
   159  
   160  func (m *manager) HasMember(ctx context.Context, gid *grouppb.GroupId, uid *userpb.UserId) (bool, error) {
   161  	members, err := m.GetMembers(ctx, gid)
   162  	if err != nil {
   163  		return false, err
   164  	}
   165  
   166  	for _, u := range members {
   167  		if u.OpaqueId == uid.OpaqueId && u.Idp == uid.Idp {
   168  			return true, nil
   169  		}
   170  	}
   171  	return false, nil
   172  }