Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(GraphQl): Allow case insensitive auth header for graphql subscriptions. #6141

Merged
merged 11 commits into from
Aug 12, 2020
74 changes: 74 additions & 0 deletions graphql/e2e/subscription/subscription_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -864,3 +864,77 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend
require.NoError(t, err)
require.Nil(t, res)
}

func TestSubscriptionAuthHeaderCaseInsensitive(t *testing.T) {
dg, err := testutil.DgraphClient(groupOnegRPC)
require.NoError(t, err)
testutil.DropAll(t, dg)

add := &common.GraphQLParams{
Query: `mutation updateGQLSchema($sch: String!) {
updateGQLSchema(input: { set: { schema: $sch }}) {
gqlSchema {
schema
}
}
}`,
Variables: map[string]interface{}{"sch": schAuth},
}
addResult := add.ExecuteAsPost(t, adminEndpoint)
require.Nil(t, addResult.Errors)
time.Sleep(time.Second * 2)

metaInfo := &testutil.AuthMeta{
PublicKey: "secret",
Namespace: "https://dgraph.io",
Algo: "HS256",
Header: "authorization",
}
metaInfo.AuthVars = map[string]interface{}{
"USER": "jatin",
"ROLE": "USER",
}

add = &common.GraphQLParams{
Query: `mutation{
addTodo(input: [
{text : "GraphQL is exciting!!",
owner : "jatin"}
])
{
todo{
text
owner
}
}
}`,
}

addResult = add.ExecuteAsPost(t, graphQLEndpoint)
require.Nil(t, addResult.Errors)

jwtToken, err := metaInfo.GetSignedToken("secret", 10*time.Second)
require.NoError(t, err)

payload := fmt.Sprintf(`{"Authorization": "%s"}`, jwtToken)
subscriptionClient, err := common.NewGraphQLSubscription(subscriptionEndpoint, &schema.Request{
Query: `subscription{
queryTodo{
owner
text
}
}`,
}, payload)
require.Nil(t, err)

res, err := subscriptionClient.RecvMsg()
require.NoError(t, err)

var resp common.GraphQLResponse
err = json.Unmarshal(res, &resp)
require.NoError(t, err)

require.Nil(t, resp.Errors)
require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`,
string(resp.Data))
}
24 changes: 13 additions & 11 deletions graphql/web/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@ import (
"compress/gzip"
"context"
"encoding/json"
"github.com/dgrijalva/jwt-go/v4"
"google.golang.org/grpc/metadata"
"strconv"
"time"

"io"
"io/ioutil"
"mime"
"net/http"
"strconv"
"strings"
"time"

"github.com/dgraph-io/dgraph/graphql/api"
"github.com/dgraph-io/dgraph/graphql/authorization"
Expand All @@ -38,9 +35,11 @@ import (
"github.com/dgraph-io/dgraph/graphql/subscription"
"github.com/dgraph-io/dgraph/x"
"github.com/dgraph-io/graphql-transport-ws/graphqlws"
"github.com/dgrijalva/jwt-go/v4"
"github.com/golang/glog"
"github.com/pkg/errors"
"go.opencensus.io/trace"
"google.golang.org/grpc/metadata"
)

type Headerkey string
Expand Down Expand Up @@ -119,7 +118,7 @@ type graphqlSubscription struct {

func (gs *graphqlSubscription) Subscribe(
ctx context.Context,
document string,
document,
operationName string,
variableValues map[string]interface{}) (payloads <-chan interface{},
err error) {
Expand All @@ -138,19 +137,22 @@ func (gs *graphqlSubscription) Subscribe(
}

name := authorization.GetHeader()
val, ok := payload[name].(string)
if ok {

for key, val := range payload {
if !strings.EqualFold(key, name) {
continue
}
md := metadata.New(map[string]string{
"authorizationJwt": val,
"authorizationJwt": val.(string),
})
ctx = metadata.NewIncomingContext(ctx, md)

ctx = metadata.NewIncomingContext(ctx, md)
customClaims, err = authorization.ExtractCustomClaims(ctx)
if err != nil {
return nil, err
}
break
}

}
// for the cases when no expiry is given in jwt or subscription doesn't have any authorization,
// we set their expiry to zero time
Expand Down