Skip to content

Commit

Permalink
Merge pull request #447 from 99designs/disable-introspection
Browse files Browse the repository at this point in the history
Add config option to disable introspection
  • Loading branch information
vektah authored Nov 28, 2018
2 parents e4bad0e + 6bea1d8 commit 6a02657
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 77 deletions.
2 changes: 0 additions & 2 deletions codegen/object_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ func (cfg *Config) buildObject(types NamedTypes, typ *ast.Definition) (*Object,
obj.Fields = append(obj.Fields, Field{
Type: &Type{types["__Schema"], []string{modPtr}, ast.NamedType("__Schema", nil), nil},
GQLName: "__schema",
NoErr: true,
GoFieldType: GoFieldMethod,
GoReceiverName: "ec",
GoFieldName: "introspectSchema",
Expand All @@ -125,7 +124,6 @@ func (cfg *Config) buildObject(types NamedTypes, typ *ast.Definition) (*Object,
obj.Fields = append(obj.Fields, Field{
Type: &Type{types["__Type"], []string{modPtr}, ast.NamedType("__Schema", nil), nil},
GQLName: "__type",
NoErr: true,
GoFieldType: GoFieldMethod,
GoReceiverName: "ec",
GoFieldName: "introspectType",
Expand Down
2 changes: 1 addition & 1 deletion codegen/templates/data.go

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions codegen/templates/generated.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,18 @@ func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}
return res
}

func (ec *executionContext) introspectSchema() *introspection.Schema {
return introspection.WrapSchema(parsedSchema)
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
return introspection.WrapSchema(parsedSchema), nil
}

func (ec *executionContext) introspectType(name string) *introspection.Type {
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name])
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
}

var parsedSchema = gqlparser.MustLoadSchema(
Expand Down
19 changes: 13 additions & 6 deletions codegen/testserver/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions codegen/testserver/generated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"testing"
"time"

"github.com/99designs/gqlgen/graphql/introspection"

"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/handler"
Expand Down Expand Up @@ -188,6 +190,62 @@ func TestGeneratedServer(t *testing.T) {
})
}

func TestIntrospection(t *testing.T) {
t.Run("disabled", func(t *testing.T) {
resolvers := &testResolver{tick: make(chan string, 1)}

srv := httptest.NewServer(
handler.GraphQL(
NewExecutableSchema(Config{Resolvers: resolvers}),
handler.IntrospectionEnabled(false),
),
)

c := client.New(srv.URL)

var resp interface{}
err := c.Post(introspection.Query, &resp)
require.EqualError(t, err, "[{\"message\":\"introspection disabled\",\"path\":[\"__schema\"]}]")
})

t.Run("enabled by default", func(t *testing.T) {
resolvers := &testResolver{tick: make(chan string, 1)}

srv := httptest.NewServer(
handler.GraphQL(
NewExecutableSchema(Config{Resolvers: resolvers}),
),
)

c := client.New(srv.URL)

var resp interface{}
err := c.Post(introspection.Query, &resp)
require.NoError(t, err)
})

t.Run("disabled by middleware", func(t *testing.T) {
resolvers := &testResolver{tick: make(chan string, 1)}

srv := httptest.NewServer(
handler.GraphQL(
NewExecutableSchema(Config{Resolvers: resolvers}),
handler.RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
graphql.GetRequestContext(ctx).DisableIntrospection = true

return next(ctx)
}),
),
)

c := client.New(srv.URL)

var resp interface{}
err := c.Post(introspection.Query, &resp)
require.EqualError(t, err, "[{\"message\":\"introspection disabled\",\"path\":[\"__schema\"]}]")
})
}

var _ graphql.Tracer = (*testTracer)(nil)

type testTracer struct {
Expand Down
40 changes: 40 additions & 0 deletions docs/content/reference/introspection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: 'Disabling introspection'
description: Prevent users from introspecting schemas in production.
linkTitle: Introspection
menu: { main: { parent: 'reference' } }
---

One of the best features of GraphQL is it's powerful discoverability, but sometimes you don't want to allow others to explore your endpoint.

## Disable introspection for the whole server

To turn introspection on and off at runtime, pass the `IntrospectionEnabled` handler option when starting the server:

```go
srv := httptest.NewServer(
handler.GraphQL(
NewExecutableSchema(Config{Resolvers: resolvers}),
handler.IntrospectionEnabled(false),
),
)
```

## Disabling introspection based on authentication

Introspection can also be enabled on a per-request context basis. For example, you could modify it in a middleware based on user authentication:

```go
srv := httptest.NewServer(
handler.GraphQL(
NewExecutableSchema(Config{Resolvers: resolvers}),
handler.RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
if userForContext(ctx).IsAdmin {
graphql.GetRequestContext(ctx).DisableIntrospection = true
}

return next(ctx)
}),
),
)
```
19 changes: 13 additions & 6 deletions example/chat/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 13 additions & 6 deletions example/config/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 13 additions & 6 deletions example/dataloader/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 13 additions & 6 deletions example/scalars/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 6a02657

Please sign in to comment.