@@ -110,14 +110,16 @@ func getAuthSelector(queryType schema.QueryType) func(t schema.Type) *schema.Rul
110110 return queryAuthSelector
111111}
112112
113- // Rewrite rewrites a GraphQL query into DQL.
113+ // Rewrite rewrites a GraphQL query into DQL. It also returns any DQL variable
114+ // bindings (e.g. parameterized password values) that must be passed to the
115+ // executor alongside the query string.
114116func (qr * queryRewriter ) Rewrite (
115117 ctx context.Context ,
116- gqlQuery schema.Query ) ([]* dql.GraphQuery , error ) {
118+ gqlQuery schema.Query ) ([]* dql.GraphQuery , map [ string ] string , error ) {
117119
118120 customClaims , err := gqlQuery .GetAuthMeta ().ExtractCustomClaims (ctx )
119121 if err != nil {
120- return nil , err
122+ return nil , nil , err
121123 }
122124
123125 authRw := & authRewriter {
@@ -143,29 +145,30 @@ func (qr *queryRewriter) Rewrite(
143145 // ATM, I'm not sure how to hook into the GraphQL validator to get that to happen
144146 xid , uid , err := gqlQuery .IDArgValue ()
145147 if err != nil {
146- return nil , err
148+ return nil , nil , err
147149 }
148150
149151 dgQuery := rewriteAsGet (gqlQuery , uid , xid , authRw )
150- return dgQuery , nil
152+ return dgQuery , nil , nil
151153 case schema .SimilarByIdQuery :
152154 xid , uid , err := gqlQuery .IDArgValue ()
153155 if err != nil {
154- return nil , err
156+ return nil , nil , err
155157 }
156- return rewriteAsSimilarByIdQuery (gqlQuery , uid , xid , authRw ), nil
158+ return rewriteAsSimilarByIdQuery (gqlQuery , uid , xid , authRw ), nil , nil
157159 case schema .SimilarByEmbeddingQuery :
158- return rewriteAsSimilarByEmbeddingQuery (gqlQuery , authRw ), nil
160+ return rewriteAsSimilarByEmbeddingQuery (gqlQuery , authRw ), nil , nil
159161 case schema .FilterQuery :
160- return rewriteAsQuery (gqlQuery , authRw ), nil
162+ return rewriteAsQuery (gqlQuery , authRw ), nil , nil
161163 case schema .PasswordQuery :
162164 return passwordQuery (gqlQuery , authRw )
163165 case schema .AggregateQuery :
164- return aggregateQuery (gqlQuery , authRw ), nil
166+ return aggregateQuery (gqlQuery , authRw ), nil , nil
165167 case schema .EntitiesQuery :
166- return entitiesQuery (gqlQuery , authRw )
168+ queries , err := entitiesQuery (gqlQuery , authRw )
169+ return queries , nil , err
167170 default :
168- return nil , errors .Errorf ("unimplemented query type %s" , gqlQuery .QueryType ())
171+ return nil , nil , errors .Errorf ("unimplemented query type %s" , gqlQuery .QueryType ())
169172 }
170173}
171174
@@ -340,17 +343,18 @@ func aggregateQuery(query schema.Query, authRw *authRewriter) []*dql.GraphQuery
340343 return append ([]* dql.GraphQuery {finalMainQuery }, dgQuery ... )
341344}
342345
343- func passwordQuery (m schema.Query , authRw * authRewriter ) ([]* dql.GraphQuery , error ) {
346+ func passwordQuery (m schema.Query , authRw * authRewriter ) (
347+ []* dql.GraphQuery , map [string ]string , error ) {
344348 xid , uid , err := m .IDArgValue ()
345349 if err != nil {
346- return nil , err
350+ return nil , nil , err
347351 }
348352
349353 dgQuery := rewriteAsGet (m , uid , xid , authRw )
350354
351355 // Handle empty dgQuery
352356 if strings .HasSuffix (dgQuery [0 ].Attr , "()" ) {
353- return dgQuery , nil
357+ return dgQuery , nil , nil
354358 }
355359
356360 // mainQuery is the query with check<Type>Password as Attr.
@@ -362,15 +366,24 @@ func passwordQuery(m schema.Query, authRw *authRewriter) ([]*dql.GraphQuery, err
362366 predicate := queriedType .DgraphPredicate (name )
363367 password := m .ArgValue (name ).(string )
364368
369+ // Parameterize the password as a DQL variable so the value is bound by
370+ // the executor rather than interpolated into the query string. This
371+ // prevents DQL injection via passwords containing characters such as
372+ // a double-quote.
373+ const pwdVar = "$pwd0"
374+ if mainQuery .Args == nil {
375+ mainQuery .Args = make (map [string ]string )
376+ }
377+ mainQuery .Args [pwdVar ] = "string"
378+
365379 // This adds the checkPwd function
366380 op := & dql.GraphQuery {
367381 Attr : "checkPwd" ,
368382 Func : mainQuery .Func ,
369383 Filter : mainQuery .Filter ,
370384 Children : []* dql.GraphQuery {{
371- Var : "pwd" ,
372- Attr : fmt .Sprintf (`checkpwd(%s, "%s")` , predicate ,
373- password ),
385+ Var : "pwd" ,
386+ Attr : fmt .Sprintf (`checkpwd(%s, %s)` , predicate , pwdVar ),
374387 }},
375388 }
376389
@@ -397,7 +410,7 @@ func passwordQuery(m schema.Query, authRw *authRewriter) ([]*dql.GraphQuery, err
397410
398411 mainQuery .Filter = ft
399412
400- return append (dgQuery , op ), nil
413+ return append (dgQuery , op ), map [ string ] string { pwdVar : password }, nil
401414}
402415
403416func intersection (a , b []uint64 ) []uint64 {
0 commit comments