@@ -99,14 +99,16 @@ func getAuthSelector(queryType schema.QueryType) func(t schema.Type) *schema.Rul
9999 return queryAuthSelector
100100}
101101
102- // Rewrite rewrites a GraphQL query into DQL.
102+ // Rewrite rewrites a GraphQL query into DQL. It also returns any DQL variable
103+ // bindings (e.g. parameterized password values) that must be passed to the
104+ // executor alongside the query string.
103105func (qr * queryRewriter ) Rewrite (
104106 ctx context.Context ,
105- gqlQuery schema.Query ) ([]* dql.GraphQuery , error ) {
107+ gqlQuery schema.Query ) ([]* dql.GraphQuery , map [ string ] string , error ) {
106108
107109 customClaims , err := gqlQuery .GetAuthMeta ().ExtractCustomClaims (ctx )
108110 if err != nil {
109- return nil , err
111+ return nil , nil , err
110112 }
111113
112114 authRw := & authRewriter {
@@ -132,29 +134,30 @@ func (qr *queryRewriter) Rewrite(
132134 // ATM, I'm not sure how to hook into the GraphQL validator to get that to happen
133135 xid , uid , err := gqlQuery .IDArgValue ()
134136 if err != nil {
135- return nil , err
137+ return nil , nil , err
136138 }
137139
138140 dgQuery := rewriteAsGet (gqlQuery , uid , xid , authRw )
139- return dgQuery , nil
141+ return dgQuery , nil , nil
140142 case schema .SimilarByIdQuery :
141143 xid , uid , err := gqlQuery .IDArgValue ()
142144 if err != nil {
143- return nil , err
145+ return nil , nil , err
144146 }
145- return rewriteAsSimilarByIdQuery (gqlQuery , uid , xid , authRw ), nil
147+ return rewriteAsSimilarByIdQuery (gqlQuery , uid , xid , authRw ), nil , nil
146148 case schema .SimilarByEmbeddingQuery :
147- return rewriteAsSimilarByEmbeddingQuery (gqlQuery , authRw ), nil
149+ return rewriteAsSimilarByEmbeddingQuery (gqlQuery , authRw ), nil , nil
148150 case schema .FilterQuery :
149- return rewriteAsQuery (gqlQuery , authRw ), nil
151+ return rewriteAsQuery (gqlQuery , authRw ), nil , nil
150152 case schema .PasswordQuery :
151153 return passwordQuery (gqlQuery , authRw )
152154 case schema .AggregateQuery :
153- return aggregateQuery (gqlQuery , authRw ), nil
155+ return aggregateQuery (gqlQuery , authRw ), nil , nil
154156 case schema .EntitiesQuery :
155- return entitiesQuery (gqlQuery , authRw )
157+ queries , err := entitiesQuery (gqlQuery , authRw )
158+ return queries , nil , err
156159 default :
157- return nil , errors .Errorf ("unimplemented query type %s" , gqlQuery .QueryType ())
160+ return nil , nil , errors .Errorf ("unimplemented query type %s" , gqlQuery .QueryType ())
158161 }
159162}
160163
@@ -329,17 +332,18 @@ func aggregateQuery(query schema.Query, authRw *authRewriter) []*dql.GraphQuery
329332 return append ([]* dql.GraphQuery {finalMainQuery }, dgQuery ... )
330333}
331334
332- func passwordQuery (m schema.Query , authRw * authRewriter ) ([]* dql.GraphQuery , error ) {
335+ func passwordQuery (m schema.Query , authRw * authRewriter ) (
336+ []* dql.GraphQuery , map [string ]string , error ) {
333337 xid , uid , err := m .IDArgValue ()
334338 if err != nil {
335- return nil , err
339+ return nil , nil , err
336340 }
337341
338342 dgQuery := rewriteAsGet (m , uid , xid , authRw )
339343
340344 // Handle empty dgQuery
341345 if strings .HasSuffix (dgQuery [0 ].Attr , "()" ) {
342- return dgQuery , nil
346+ return dgQuery , nil , nil
343347 }
344348
345349 // mainQuery is the query with check<Type>Password as Attr.
@@ -351,15 +355,24 @@ func passwordQuery(m schema.Query, authRw *authRewriter) ([]*dql.GraphQuery, err
351355 predicate := queriedType .DgraphPredicate (name )
352356 password := m .ArgValue (name ).(string )
353357
358+ // Parameterize the password as a DQL variable so the value is bound by
359+ // the executor rather than interpolated into the query string. This
360+ // prevents DQL injection via passwords containing characters such as
361+ // a double-quote.
362+ const pwdVar = "$pwd0"
363+ if mainQuery .Args == nil {
364+ mainQuery .Args = make (map [string ]string )
365+ }
366+ mainQuery .Args [pwdVar ] = "string"
367+
354368 // This adds the checkPwd function
355369 op := & dql.GraphQuery {
356370 Attr : "checkPwd" ,
357371 Func : mainQuery .Func ,
358372 Filter : mainQuery .Filter ,
359373 Children : []* dql.GraphQuery {{
360- Var : "pwd" ,
361- Attr : fmt .Sprintf (`checkpwd(%s, "%s")` , predicate ,
362- password ),
374+ Var : "pwd" ,
375+ Attr : fmt .Sprintf (`checkpwd(%s, %s)` , predicate , pwdVar ),
363376 }},
364377 }
365378
@@ -386,7 +399,7 @@ func passwordQuery(m schema.Query, authRw *authRewriter) ([]*dql.GraphQuery, err
386399
387400 mainQuery .Filter = ft
388401
389- return append (dgQuery , op ), nil
402+ return append (dgQuery , op ), map [ string ] string { pwdVar : password }, nil
390403}
391404
392405func intersection (a , b []uint64 ) []uint64 {
0 commit comments