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

feat(GraphQL): Add support for passing OAuth Bearer token as authorization JWT (GRAPHQL-1049) #7490

Merged
merged 1 commit into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions graphql/authorization/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,24 +196,34 @@ func (a *AuthMeta) GetHeader() string {
}

// AttachAuthorizationJwt adds any incoming JWT authorization data into the grpc context metadata.
func (a *AuthMeta) AttachAuthorizationJwt(ctx context.Context, header http.Header) context.Context {
func (a *AuthMeta) AttachAuthorizationJwt(ctx context.Context,
header http.Header) (context.Context, error) {
if a == nil {
return ctx
return ctx, nil
}

authorizationJwt := header.Get(a.Header)
if authorizationJwt == "" {
return ctx
authHeaderVal := header.Get(a.Header)
if authHeaderVal == "" {
return ctx, nil
}

if strings.HasPrefix(strings.ToLower(authHeaderVal), "bearer ") {
parts := strings.Split(authHeaderVal, " ")
if len(parts) != 2 {
return ctx, fmt.Errorf("invalid Bearer-formatted header value for JWT (%s)",
authHeaderVal)
}
authHeaderVal = parts[1]
}

md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(nil)
}

md.Append(string(AuthJwtCtxKey), authorizationJwt)
md.Append(string(AuthJwtCtxKey), authHeaderVal)
ctx = metadata.NewIncomingContext(ctx, md)
return ctx
return ctx, nil
}

type CustomClaims struct {
Expand Down
25 changes: 25 additions & 0 deletions graphql/e2e/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,31 @@ func TestAuthRulesWithMissingJWT(t *testing.T) {
}
}

func TestBearerToken(t *testing.T) {
queryProjectParams := &common.GraphQLParams{
Query: `
query {
queryProject {
name
}
}`,
Headers: http.Header{},
}

// querying with a bad bearer token should give back an error
queryProjectParams.Headers.Set(metaInfo.Header, "Bearer bad token")
resp := queryProjectParams.ExecuteAsPost(t, common.GraphqlURL)
require.Contains(t, resp.Errors.Error(), "invalid Bearer-formatted header value for JWT (Bearer bad token)")
require.Nil(t, resp.Data)

// querying with a correct bearer token should give back expected results
queryProjectParams.Headers.Set(metaInfo.Header, "Bearer "+common.GetJWT(t, "user1", "",
metaInfo).Get(metaInfo.Header))
resp = queryProjectParams.ExecuteAsPost(t, common.GraphqlURL)
common.RequireNoGQLErrors(t, resp)
testutil.CompareJSON(t, `{"queryProject":[{"name":"Project1"}]}`, string(resp.Data))
}

func TestOrderAndOffset(t *testing.T) {
tasks := Tasks{
Task{
Expand Down
6 changes: 5 additions & 1 deletion graphql/resolve/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,11 @@ func (r *RequestResolver) Resolve(ctx context.Context, gqlReq *schema.Request) *
ctx = context.WithValue(ctx, resolveStartTime, startTime)

// Pass in GraphQL @auth information
ctx = r.schema.Meta().AuthMeta().AttachAuthorizationJwt(ctx, gqlReq.Header)
ctx, err := r.schema.Meta().AuthMeta().AttachAuthorizationJwt(ctx, gqlReq.Header)
if err != nil {
return schema.ErrorResponse(err)
}

ctx = x.AttachJWTNamespace(ctx)
op, err := r.schema.Operation(gqlReq)
if err != nil {
Expand Down
7 changes: 5 additions & 2 deletions graphql/subscription/poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,11 @@ func (p *Poller) AddSubscriber(req *schema.Request) (*SubscriberResponse, error)
// find out the custom claims for auth, if any. As,
// We also need to use authVariables in generating the hashed bucketID
authMeta := resolver.Schema().Meta().AuthMeta()
customClaims, err := authMeta.ExtractCustomClaims(authMeta.AttachAuthorizationJwt(context.
Background(), req.Header))
ctx, err := authMeta.AttachAuthorizationJwt(context.Background(), req.Header)
if err != nil {
return nil, err
}
customClaims, err := authMeta.ExtractCustomClaims(ctx)
if err != nil {
return nil, err
}
Expand Down