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

AsMap with map[string]interface{} cannot set nil value #1

Closed
qneyrat opened this issue Jan 7, 2021 · 3 comments · Fixed by #2
Closed

AsMap with map[string]interface{} cannot set nil value #1

qneyrat opened this issue Jan 7, 2021 · 3 comments · Fixed by #2

Comments

@qneyrat
Copy link

qneyrat commented Jan 7, 2021

AsMap cannot handle nil value.
In case, you run jwt.Token.AsMap with claim "foo" is type map (zero value is nil) is "null" in jwt.
When you call AsMap on it, it throw panic "panic: reflect: call of reflect.Value.Type on zero Value".
It's normal because reflect.ValueOf(nil) has not type because is nil but if dst is map type it's settable.
You can run this to reproduce:

func TestAsMap(t *testing.T) {
	t.Run("maps", func(t *testing.T) {
		inputs := []interface{}{
			map[string]interface{}{
				"foo": "one",
				"bar": "two",
				"baz": nil,
			},
		}
		for _, x := range inputs {
			input := x
			t.Run(fmt.Sprintf("%T", input), func(t *testing.T) {
				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
				defer cancel()
				dst := reflect.New(reflect.TypeOf(input))
				dst.Elem().Set(reflect.MakeMap(reflect.TypeOf(input)))
				if !assert.NoError(t, mapiter.AsMap(ctx, input, dst.Interface()), `mapiter.AsMap should succeed`) {
					return
				}
				if !assert.Equal(t, input, dst.Elem().Interface(), `maps should be the same`) {
					return
				}
			})
		}
	})
}
@MattBrittan
Copy link

I have encountered the same issue (token contained "user_access": null); currently using the below hack to prevent panics (with jwt).

package main

import (
	"context"

	"github.com/lestrrat-go/jwx/jwt"
)

func main() {
	token := jwt.New()
	token.Set("test", interface{}(nil))
	fixToken(token)

	// Below will not panic
	_, _ = token.AsMap(context.Background())

	// Demonstrate issue if hack is not included (will panic)
	token.Set("test", interface{}(nil))
	_, _ = token.AsMap(context.Background())
}

// fixToken removes interface{}(nil) values from the token because they cause panics in iter.AsMap
func fixToken(token jwt.Token) {
	// Hacky Fix for https://github.com/lestrrat-go/iter/issues/1
	token.Walk(context.Background(), VisitorFunc(func(k string, v interface{}) error {
		if v == interface{}(nil) {
			token.Remove(k)
		}
		return nil
	}))
}

// VisitorFunc is a type of Visitor based on a function
type VisitorFunc func(string, interface{}) error

func (fn VisitorFunc) Visit(s string, v interface{}) error {
	return fn(s, v)
}

@lestrrat
Copy link
Contributor

Oh oops, sorry I didn't realize this existed until now. Reading...

lestrrat added a commit that referenced this issue Mar 28, 2021
Check for reflect.Invalid == value.Kind()
@lestrrat
Copy link
Contributor

Hi, thanks for the report, and sorry for not noticing this sooner.
I will cut a release and update jwx shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants