@@ -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.
4449func (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
461470func 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
701733func 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+
10721163func removeFilters (f * gql.FilterTree , blockedPreds map [string ]struct {}) * gql.FilterTree {
10731164 if f == nil {
10741165 return nil
0 commit comments