Skip to content

Commit

Permalink
feat(GraphQL): Adds auth for subscriptions (#5984)
Browse files Browse the repository at this point in the history
* removed log info

* added missing functions in auth.go

* resolved merge issues

* added authvariable code for subscriptions

* removed a print statement

* removed authvariable function and changed it's occurences

* resolved review comments

* replaced gophers library to our own

* added test

* Fix build error by using latest version of dgraph-io/graphql-transport-ws

* Fix the audience unit tests

* Fix formatting

* fix for subscription withou auth

* fixed subscription error

* added auth test

* resolved pawan's comments.

* latest code.

* Delete p,w and zw from checked in code

* Use jwt.At function so that time.IsZero returns correctly

* modified test

* Complete the test

* Add another test cases to check subscription ends after JWT expires

* added test for multiple subscriptions

* added test for multiple subscriptions with different jw data

* clean code

* modified subscriptions test

* Fix the test

* addresses review comments.

* edited few comments

* Remove subscriptionID from subscriber

* Run go mod tidy to fix the go.mod and go.sum files

* Clean up some code

* Revert "Clean up some code"

This reverts commit 3922649.

* Fix failures in custom logic test

* fixed deepsource error

* fixed auth test

Co-authored-by: Pawan Rawal <[email protected]>
Co-authored-by: JatinDevDG <[email protected]>
  • Loading branch information
3 people authored Jul 20, 2020
1 parent 55625ec commit 5f81aac
Show file tree
Hide file tree
Showing 15 changed files with 825 additions and 99 deletions.
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200715005050-3ffaf3cd1d4a
github.com/dgraph-io/dgo/v200 v200.0.0-20200401175452-e463f9234453
github.com/dgraph-io/graphql-transport-ws v0.0.0-20200715131837-c0460019ead2
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1
Expand All @@ -36,7 +37,7 @@ require (
github.com/google/uuid v1.0.0
github.com/gorilla/websocket v1.4.1
github.com/graph-gophers/graphql-go v0.0.0-20200309224638-dae41bde9ef9
github.com/graph-gophers/graphql-transport-ws v0.0.0-20190611222414-40c048432299
github.com/graph-gophers/graphql-transport-ws v0.0.0-20190611222414-40c048432299 // indirect
github.com/hashicorp/vault/api v1.0.4
github.com/minio/minio-go/v6 v6.0.55
github.com/mitchellh/panicwrap v1.0.0
Expand All @@ -62,7 +63,7 @@ require (
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9
golang.org/x/text v0.3.2
google.golang.org/genproto v0.0.0-20190516172635-bb713bdc0e52 // indirect
google.golang.org/grpc v1.23.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200711090415-0dfb8b45d4a4 h1:M85aROJxDOXmp8mZQN6x04EraKDGOF2RL3ox/6LZdjo=
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200711090415-0dfb8b45d4a4/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200715005050-3ffaf3cd1d4a h1:k8A4B5IEFzH33Px1N7K0FpMszEFTZGQb7HCRBslMB+s=
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200715005050-3ffaf3cd1d4a/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
github.com/dgraph-io/dgo/v200 v200.0.0-20200401175452-e463f9234453 h1:DTgOrw91nMIukDm/WEvdobPLl0LgeDd/JE66+24jBks=
github.com/dgraph-io/dgo/v200 v200.0.0-20200401175452-e463f9234453/go.mod h1:Co+FwJrnndSrPORO8Gdn20dR7FPTfmXr0W/su0Ve/Ig=
github.com/dgraph-io/graphql-transport-ws v0.0.0-20200715131837-c0460019ead2 h1:NSl3XXyON9bgmBJSAvr5FPrgILAovtoTs7FwdtaZZq0=
github.com/dgraph-io/graphql-transport-ws v0.0.0-20200715131837-c0460019ead2/go.mod h1:7z3c/5w0sMYYZF5bHsrh8IH4fKwG5O5Y70cPH1ZLLRQ=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
Expand Down Expand Up @@ -507,8 +507,8 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
Expand Down
39 changes: 20 additions & 19 deletions graphql/authorization/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ import (
)

type ctxKey string
type authVariablekey string

const (
AuthJwtCtxKey = ctxKey("authorizationJwt")
AuthVariables = authVariablekey("authVariable")
RSA256 = "RS256"
HMAC256 = "HS256"
AuthMetaHeader = "# Dgraph.Authorization "
Expand Down Expand Up @@ -207,22 +209,6 @@ func (c *CustomClaims) UnmarshalJSON(data []byte) error {
return nil
}

func ExtractAuthVariables(ctx context.Context) (map[string]interface{}, error) {
// Extract the jwt and unmarshal the jwt to get the auth variables.
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, nil
}

jwtToken := md.Get(string(AuthJwtCtxKey))
if len(jwtToken) == 0 {
return nil, nil
} else if len(jwtToken) > 1 {
return nil, fmt.Errorf("invalid jwt auth token")
}
return validateToken(jwtToken[0])
}

func (c *CustomClaims) validateAudience() error {
// If there's no audience claim, ignore
if c.Audience == nil || len(c.Audience) == 0 {
Expand All @@ -249,7 +235,23 @@ func (c *CustomClaims) validateAudience() error {
return nil
}

func validateToken(jwtStr string) (map[string]interface{}, error) {
func ExtractCustomClaims(ctx context.Context) (*CustomClaims, error) {
// return CustomClaims containing jwt and authvariables.
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return &CustomClaims{}, nil
}

jwtToken := md.Get(string(AuthJwtCtxKey))
if len(jwtToken) == 0 {
return &CustomClaims{}, nil
} else if len(jwtToken) > 1 {
return nil, fmt.Errorf("invalid jwt auth token")
}
return validateJWTCustomClaims(jwtToken[0])
}

func validateJWTCustomClaims(jwtStr string) (*CustomClaims, error) {
if metainfo.Algo == "" {
return nil, fmt.Errorf(
"jwt token cannot be validated because verification algorithm is not set")
Expand Down Expand Up @@ -289,6 +291,5 @@ func validateToken(jwtStr string) (map[string]interface{}, error) {
if err := claims.validateAudience(); err != nil {
return nil, err
}

return claims.AuthVariables, nil
return claims, nil
}
3 changes: 2 additions & 1 deletion graphql/e2e/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"os"
"strings"
"testing"
"time"

"github.com/dgraph-io/dgraph/graphql/authorization"
"github.com/dgraph-io/dgraph/graphql/e2e/common"
Expand Down Expand Up @@ -177,7 +178,7 @@ func getJWT(t *testing.T, user, role string) http.Header {
metaInfo.AuthVars["ROLE"] = role
}

jwtToken, err := metaInfo.GetSignedToken("./sample_private_key.pem")
jwtToken, err := metaInfo.GetSignedToken("./sample_private_key.pem", 300*time.Second)
require.NoError(t, err)

h := make(http.Header)
Expand Down
10 changes: 5 additions & 5 deletions graphql/e2e/common/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -1284,9 +1284,9 @@ func querynestedOnlyTypename(t *testing.T) {
},
{
"__typename": "Post"
},
},
{
"__typename": "Post"
}
]
Expand All @@ -1311,8 +1311,8 @@ func onlytypenameForInterface(t *testing.T) {
eq: [EMPIRE]
}
}) {
... on Human {
__typename
}
Expand All @@ -1326,7 +1326,7 @@ func onlytypenameForInterface(t *testing.T) {
expected := `{
"queryCharacter": [
{
"__typename": "Human"
"__typename": "Human"
},
{
"__typename": "Droid"
Expand Down
5 changes: 2 additions & 3 deletions graphql/e2e/common/subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,18 @@ type GraphQLSubscriptionClient struct {
}

// NewGraphQLSubscription returns graphql subscription client.
func NewGraphQLSubscription(url string, req *schema.Request) (*GraphQLSubscriptionClient, error) {
func NewGraphQLSubscription(url string, req *schema.Request, subscriptionPayload string) (*GraphQLSubscriptionClient, error) {
header := http.Header{
"Sec-WebSocket-Protocol": []string{protocolGraphQLWS},
}
conn, _, err := websocket.DefaultDialer.Dial(url, header)
if err != nil {
return nil, err
}

// Initialize subscription.
init := operationMessage{
Type: initMsg,
Payload: []byte(`{}`),
Payload: []byte(subscriptionPayload),
}

// Send Intialization message to the graphql server.
Expand Down
22 changes: 11 additions & 11 deletions graphql/e2e/custom_logic/custom_logic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func TestCustomQueryShouldForwardHeaders(t *testing.T) {
secretHeaders: ["Github-Api-Token"]
})
}
# Dgraph.Secret Github-Api-Token "random-fake-token"
# Dgraph.Secret app "should-be-overriden"
`
Expand Down Expand Up @@ -247,7 +247,7 @@ func TestSchemaIntrospectionForCustomQueryShouldForwardHeaders(t *testing.T) {
code: String!
name: String!
}
type Query {
myCustom(yo: CountryInput!): [Country!]!
@custom(
Expand Down Expand Up @@ -331,7 +331,7 @@ func TestCustomFieldsInSubscription(t *testing.T) {
name
}
}`,
})
}, `{}`)
require.NoError(t, err)
_, err = client.RecvMsg()
require.Contains(t, err.Error(), "Custom field `name` is not supported in graphql subscription")
Expand Down Expand Up @@ -370,7 +370,7 @@ func TestSubscriptionInNestedCustomField(t *testing.T) {
}
}
}`,
})
}, `{}`)
require.NoError(t, err)
_, err = client.RecvMsg()
require.Contains(t, err.Error(), "Custom field `anotherName` is not supported in graphql subscription")
Expand Down Expand Up @@ -1257,7 +1257,7 @@ func TestCustomLogicGraphql(t *testing.T) {
code: String
name: String
}
type Query {
getCountry1(id: ID!): Country!
@custom(
Expand Down Expand Up @@ -1292,7 +1292,7 @@ func TestCustomLogicGraphqlWithArgumentsOnFields(t *testing.T) {
code(size: Int!): String
name: String
}
type Query {
getCountry2(id: ID!): Country!
@custom(
Expand Down Expand Up @@ -1378,7 +1378,7 @@ func TestCustomLogicGraphQLValidArrayResponse(t *testing.T) {
code: String
name: String
}
type Query {
getCountries(id: ID!): [Country]
@custom(
Expand Down Expand Up @@ -2071,7 +2071,7 @@ func TestCustomGraphqlMissingRequiredArgument(t *testing.T) {
code: String!
name: String!
}
type Mutation {
addCountry1(input: CountryInput!): Country! @custom(http: {
url: "http://mock:8888/setCountry",
Expand Down Expand Up @@ -2134,7 +2134,7 @@ func TestCustomGraphqlMutation1(t *testing.T) {
code: String!
name: String!
}
type Mutation {
addCountry1(input: CountryInput!): Country! @custom(http: {
url: "http://mock:8888/setCountry"
Expand Down Expand Up @@ -2224,7 +2224,7 @@ func TestCustomGraphqlMutation2(t *testing.T) {
code: String!
name: String!
}
type Mutation {
updateCountries(name: String, std: Int): [Country!]! @custom(http: {
url: "http://mock:8888/updateCountries",
Expand Down Expand Up @@ -2279,7 +2279,7 @@ func TestForValidInputArgument(t *testing.T) {
code: String!
name: String!
}
type Query {
myCustom(yo: CountryInput!): [Country!]!
@custom(
Expand Down
Loading

0 comments on commit 5f81aac

Please sign in to comment.