Skip to content

Commit 6c7335b

Browse files
committed
Merge remote-tracking branch 'origin/release/v20.07' into release/v20.07-slash
2 parents c4fd66b + 052023a commit 6c7335b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+3158
-834
lines changed

edgraph/access_ee.go

Lines changed: 107 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ import (
4040
"google.golang.org/grpc/status"
4141
)
4242

43+
type predsAndvars struct {
44+
preds []string
45+
vars map[string]string
46+
}
47+
4348
// Login handles login requests from clients.
4449
func (s *Server) Login(ctx context.Context,
4550
request *api.LoginRequest) (*api.Response, error) {
@@ -172,6 +177,7 @@ func validateToken(jwtStr string) ([]string, error) {
172177
return nil, errors.Errorf("unable to parse jwt token:%v", err)
173178
}
174179

180+
// TODO(arijit): Upgrade the jwt library to v4.0
175181
claims, ok := token.Claims.(jwt.MapClaims)
176182
if !ok || !token.Valid {
177183
return nil, errors.Errorf("claims in jwt token is not map claims")
@@ -354,6 +360,9 @@ const queryAcls = `
354360
dgraph.rule.predicate
355361
dgraph.rule.permission
356362
}
363+
~dgraph.user.group{
364+
dgraph.xid
365+
}
357366
}
358367
}
359368
`
@@ -459,7 +468,7 @@ func extractUserAndGroups(ctx context.Context) ([]string, error) {
459468
}
460469

461470
func authorizePreds(userId string, groupIds, preds []string,
462-
aclOp *acl.Operation) map[string]struct{} {
471+
aclOp *acl.Operation) (map[string]struct{}, []string) {
463472

464473
blockedPreds := make(map[string]struct{})
465474
for _, pred := range preds {
@@ -475,7 +484,17 @@ func authorizePreds(userId string, groupIds, preds []string,
475484
blockedPreds[pred] = struct{}{}
476485
}
477486
}
478-
return blockedPreds
487+
aclCachePtr.RLock()
488+
allowedPreds := make([]string, len(aclCachePtr.userPredPerms[userId]))
489+
// User can have multiple permission for same predicate, add predicate
490+
// only if the acl.Op is covered in the set of permissions for the user
491+
for predicate, perm := range aclCachePtr.userPredPerms[userId] {
492+
if (perm & aclOp.Code) > 0 {
493+
allowedPreds = append(allowedPreds, predicate)
494+
}
495+
}
496+
aclCachePtr.RUnlock()
497+
return blockedPreds, allowedPreds
479498
}
480499

481500
// authorizeAlter parses the Schema in the operation and authorizes the operation
@@ -531,7 +550,7 @@ func authorizeAlter(ctx context.Context, op *api.Operation) error {
531550
"only guardians are allowed to drop all data, but the current user is %s", userId)
532551
}
533552

534-
blockedPreds := authorizePreds(userId, groupIds, preds, acl.Modify)
553+
blockedPreds, _ := authorizePreds(userId, groupIds, preds, acl.Modify)
535554
if len(blockedPreds) > 0 {
536555
var msg strings.Builder
537556
for key := range blockedPreds {
@@ -639,7 +658,7 @@ func authorizeMutation(ctx context.Context, gmu *gql.Mutation) error {
639658
return nil
640659
}
641660

642-
blockedPreds := authorizePreds(userId, groupIds, preds, acl.Write)
661+
blockedPreds, _ := authorizePreds(userId, groupIds, preds, acl.Write)
643662
if len(blockedPreds) > 0 {
644663
var msg strings.Builder
645664
for key := range blockedPreds {
@@ -669,14 +688,19 @@ func authorizeMutation(ctx context.Context, gmu *gql.Mutation) error {
669688
return err
670689
}
671690

672-
func parsePredsFromQuery(gqls []*gql.GraphQuery) []string {
691+
func parsePredsFromQuery(gqls []*gql.GraphQuery) predsAndvars {
673692
predsMap := make(map[string]struct{})
693+
varsMap := make(map[string]string)
674694
for _, gq := range gqls {
675695
if gq.Func != nil {
676696
predsMap[gq.Func.Attr] = struct{}{}
677697
}
678-
if len(gq.Attr) > 0 && gq.Attr != "uid" {
698+
if len(gq.Var) > 0 {
699+
varsMap[gq.Var] = gq.Attr
700+
}
701+
if len(gq.Attr) > 0 && gq.Attr != "uid" && gq.Attr != "expand" && gq.Attr != "val" {
679702
predsMap[gq.Attr] = struct{}{}
703+
680704
}
681705
for _, ord := range gq.Order {
682706
predsMap[ord.Attr] = struct{}{}
@@ -687,15 +711,23 @@ func parsePredsFromQuery(gqls []*gql.GraphQuery) []string {
687711
for _, pred := range parsePredsFromFilter(gq.Filter) {
688712
predsMap[pred] = struct{}{}
689713
}
690-
for _, childPred := range parsePredsFromQuery(gq.Children) {
714+
childPredandVars := parsePredsFromQuery(gq.Children)
715+
for _, childPred := range childPredandVars.preds {
691716
predsMap[childPred] = struct{}{}
692717
}
718+
for childVar := range childPredandVars.vars {
719+
varsMap[childVar] = childPredandVars.vars[childVar]
720+
}
693721
}
694722
preds := make([]string, 0, len(predsMap))
695723
for pred := range predsMap {
696-
preds = append(preds, pred)
724+
if _, found := varsMap[pred]; !found {
725+
preds = append(preds, pred)
726+
}
697727
}
698-
return preds
728+
729+
pv := predsAndvars{preds: preds, vars: varsMap}
730+
return pv
699731
}
700732

701733
func parsePredsFromFilter(f *gql.FilterTree) []string {
@@ -742,26 +774,36 @@ func authorizeQuery(ctx context.Context, parsedReq *gql.Result, graphql bool) er
742774

743775
var userId string
744776
var groupIds []string
745-
preds := parsePredsFromQuery(parsedReq.Query)
777+
predsAndvars := parsePredsFromQuery(parsedReq.Query)
778+
preds := predsAndvars.preds
779+
varsToPredMap := predsAndvars.vars
780+
781+
// Need this to efficiently identify blocked variables from the
782+
// list of blocked predicates
783+
predToVarsMap := make(map[string]string)
784+
for k, v := range varsToPredMap {
785+
predToVarsMap[v] = k
786+
}
746787

747-
doAuthorizeQuery := func() (map[string]struct{}, error) {
788+
doAuthorizeQuery := func() (map[string]struct{}, []string, error) {
748789
userData, err := extractUserAndGroups(ctx)
749790
if err != nil {
750-
return nil, status.Error(codes.Unauthenticated, err.Error())
791+
return nil, nil, status.Error(codes.Unauthenticated, err.Error())
751792
}
752793

753794
userId = userData[0]
754795
groupIds = userData[1:]
755796

756797
if x.IsGuardian(groupIds) {
757798
// Members of guardian groups are allowed to query anything.
758-
return nil, nil
799+
return nil, nil, nil
759800
}
760801

761-
return authorizePreds(userId, groupIds, preds, acl.Read), nil
802+
blockedPreds, allowedPreds := authorizePreds(userId, groupIds, preds, acl.Read)
803+
return blockedPreds, allowedPreds, nil
762804
}
763805

764-
blockedPreds, err := doAuthorizeQuery()
806+
blockedPreds, allowedPreds, err := doAuthorizeQuery()
765807

766808
if span := otrace.FromContext(ctx); span != nil {
767809
span.Annotatef(nil, (&accessEntry{
@@ -792,7 +834,21 @@ func authorizeQuery(ctx context.Context, parsedReq *gql.Result, graphql bool) er
792834
// In query context ~predicate and predicate are considered different.
793835
delete(blockedPreds, "~dgraph.user.group")
794836
}
837+
838+
blockedVars := make(map[string]struct{})
839+
for predicate := range blockedPreds {
840+
if variable, found := predToVarsMap[predicate]; found {
841+
// Add variables to blockedPreds to delete from Query
842+
blockedPreds[variable] = struct{}{}
843+
// Collect blocked Variables to remove from QueryVars
844+
blockedVars[variable] = struct{}{}
845+
}
846+
}
795847
parsedReq.Query = removePredsFromQuery(parsedReq.Query, blockedPreds)
848+
parsedReq.QueryVars = removeVarsFromQueryVars(parsedReq.QueryVars, blockedVars)
849+
}
850+
for i := range parsedReq.Query {
851+
parsedReq.Query[i].AllowedPreds = allowedPreds
796852
}
797853

798854
return nil
@@ -832,8 +888,9 @@ func authorizeSchemaQuery(ctx context.Context, er *query.ExecutionResult) error
832888
// Members of guardian groups are allowed to query anything.
833889
return nil, nil
834890
}
891+
blockedPreds, _ := authorizePreds(userId, groupIds, preds, acl.Read)
835892

836-
return authorizePreds(userId, groupIds, preds, acl.Read), nil
893+
return blockedPreds, nil
837894
}
838895

839896
// find the predicates which are blocked for the schema query
@@ -1039,6 +1096,7 @@ func removePredsFromQuery(gqs []*gql.GraphQuery,
10391096
blockedPreds map[string]struct{}) []*gql.GraphQuery {
10401097

10411098
filteredGQs := gqs[:0]
1099+
L:
10421100
for _, gq := range gqs {
10431101
if gq.Func != nil && len(gq.Func.Attr) > 0 {
10441102
if _, ok := blockedPreds[gq.Func.Attr]; ok {
@@ -1049,6 +1107,15 @@ func removePredsFromQuery(gqs []*gql.GraphQuery,
10491107
if _, ok := blockedPreds[gq.Attr]; ok {
10501108
continue
10511109
}
1110+
if gq.Attr == "val" {
1111+
// TODO (Anurag): If val supports multiple variables, this would
1112+
// need an upgrade
1113+
for _, variable := range gq.NeedsVar {
1114+
if _, ok := blockedPreds[variable.Name]; ok {
1115+
continue L
1116+
}
1117+
}
1118+
}
10521119
}
10531120

10541121
order := gq.Order[:0]
@@ -1069,6 +1136,30 @@ func removePredsFromQuery(gqs []*gql.GraphQuery,
10691136
return filteredGQs
10701137
}
10711138

1139+
func removeVarsFromQueryVars(gqs []*gql.Vars,
1140+
blockedVars map[string]struct{}) []*gql.Vars {
1141+
1142+
filteredGQs := gqs[:0]
1143+
for _, gq := range gqs {
1144+
var defines []string
1145+
var needs []string
1146+
for _, variable := range gq.Defines {
1147+
if _, ok := blockedVars[variable]; !ok {
1148+
defines = append(defines, variable)
1149+
}
1150+
}
1151+
for _, variable := range gq.Needs {
1152+
if _, ok := blockedVars[variable]; !ok {
1153+
needs = append(needs, variable)
1154+
}
1155+
}
1156+
gq.Defines = defines
1157+
gq.Needs = needs
1158+
filteredGQs = append(filteredGQs, gq)
1159+
}
1160+
return filteredGQs
1161+
}
1162+
10721163
func removeFilters(f *gql.FilterTree, blockedPreds map[string]struct{}) *gql.FilterTree {
10731164
if f == nil {
10741165
return nil

edgraph/acl_cache.go

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,23 @@ import (
2323
// aclCache is the cache mapping group names to the corresponding group acls
2424
type aclCache struct {
2525
sync.RWMutex
26-
predPerms map[string]map[string]int32
26+
predPerms map[string]map[string]int32
27+
userPredPerms map[string]map[string]int32
2728
}
2829

2930
var aclCachePtr = &aclCache{
30-
predPerms: make(map[string]map[string]int32),
31+
predPerms: make(map[string]map[string]int32),
32+
userPredPerms: make(map[string]map[string]int32),
3133
}
3234

3335
func (cache *aclCache) update(groups []acl.Group) {
3436
// In dgraph, acl rules are divided by groups, e.g.
3537
// the dev group has the following blob representing its ACL rules
3638
// [friend, 4], [name, 7] where friend and name are predicates,
37-
// However in the aclCachePtr in memory, we need to change the structure so
38-
// that ACL rules are divided by predicates, e.g.
39+
// However in the aclCachePtr in memory, we need to change the structure and store
40+
// the information in two formats for efficient look-ups.
41+
//
42+
// First in which ACL rules are divided by predicates, e.g.
3943
// friend ->
4044
// dev -> 4
4145
// sre -> 6
@@ -44,12 +48,27 @@ func (cache *aclCache) update(groups []acl.Group) {
4448
// the reason is that we want to efficiently determine if any ACL rule has been defined
4549
// for a given predicate, and allow the operation if none is defined, per the fail open
4650
// approach
47-
48-
// predPerms is the map descriebed above that maps a single
51+
//
52+
// Second in which ACL rules are divided by users, e.g.
53+
// user-alice ->
54+
// friend -> 4
55+
// name -> 6
56+
// user-bob ->
57+
// friend -> 7
58+
// the reason is so that we can efficiently determine a list of predicates (allowedPreds)
59+
// to which user has access for their queries
60+
61+
// predPerms is the map, described above in First, that maps a single
4962
// predicate to a submap, and the submap maps a group to a permission
63+
64+
// userPredPerms is the map, described above in Second, that maps a single
65+
// user to a submap, and the submap maps a predicate to a permission
66+
5067
predPerms := make(map[string]map[string]int32)
68+
userPredPerms := make(map[string]map[string]int32)
5169
for _, group := range groups {
5270
acls := group.Rules
71+
users := group.Users
5372

5473
for _, acl := range acls {
5574
if len(acl.Predicate) > 0 {
@@ -62,11 +81,28 @@ func (cache *aclCache) update(groups []acl.Group) {
6281
}
6382
}
6483
}
84+
85+
for _, user := range users {
86+
if _, found := userPredPerms[user.UserID]; !found {
87+
userPredPerms[user.UserID] = make(map[string]int32)
88+
}
89+
// For each user we store all the permissions available to that user
90+
// via different groups. Therefore we take OR if the user already has
91+
// a permission for a predicate
92+
for _, acl := range acls {
93+
if _, found := userPredPerms[user.UserID][acl.Predicate]; found {
94+
userPredPerms[user.UserID][acl.Predicate] |= acl.Perm
95+
} else {
96+
userPredPerms[user.UserID][acl.Predicate] = acl.Perm
97+
}
98+
}
99+
}
65100
}
66101

67102
aclCachePtr.Lock()
68103
defer aclCachePtr.Unlock()
69104
aclCachePtr.predPerms = predPerms
105+
aclCachePtr.userPredPerms = userPredPerms
70106
}
71107

72108
func (cache *aclCache) authorizePredicate(groups []string, predicate string,

0 commit comments

Comments
 (0)