Commit 3c0dbf5e authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Reliably return an error from token.Parse.

We would sometimes return nil cast to an interface with no error,
which would cause the server to crash with a null dereference.
parent dc8a78be
...@@ -120,7 +120,7 @@ func toStringArray(a []interface{}) ([]string, bool) { ...@@ -120,7 +120,7 @@ func toStringArray(a []interface{}) ([]string, bool) {
return b, true return b, true
} }
func parseJWT(token string, keys []map[string]interface{}) (Token, error) { func parseJWT(token string, keys []map[string]interface{}) (*JWT, error) {
t, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { t, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
return getKey(t.Header, keys) return getKey(t.Header, keys)
}) })
......
...@@ -55,11 +55,14 @@ func SetStatefulFilename(filename string) { ...@@ -55,11 +55,14 @@ func SetStatefulFilename(filename string) {
tokens.modTime = time.Time{} tokens.modTime = time.Time{}
} }
func getStateful(token string) (Token, error) { func getStateful(token string) (*Stateful, error) {
tokens.mu.Lock() tokens.mu.Lock()
defer tokens.mu.Unlock() defer tokens.mu.Unlock()
err := tokens.load() err := tokens.load()
if err != nil { if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err return nil, err
} }
if tokens.tokens == nil { if tokens.tokens == nil {
......
...@@ -2,6 +2,7 @@ package token ...@@ -2,6 +2,7 @@ package token
import ( import (
"errors" "errors"
"os"
) )
var ErrUsernameRequired = errors.New("username required") var ErrUsernameRequired = errors.New("username required")
...@@ -11,9 +12,23 @@ type Token interface { ...@@ -11,9 +12,23 @@ type Token interface {
} }
func Parse(token string, keys []map[string]interface{}) (Token, error) { func Parse(token string, keys []map[string]interface{}) (Token, error) {
t, err := getStateful(token) // both getStateful and parseJWT may return nil, which we
if err == nil && t != nil { // shouldn't cast into an interface. Be very careful.
return t, nil s, err1 := getStateful(token)
if err1 == nil && s != nil {
return s, nil
}
jwt, err2 := parseJWT(token, keys)
if err2 == nil && jwt != nil {
return jwt, nil
}
if err1 != nil {
return nil, err1
} else if err2 != nil {
return nil, err2
} else {
return nil, os.ErrNotExist
} }
return parseJWT(token, keys)
} }
package token
import (
"testing"
"path/filepath"
"os"
)
func TestBad(t *testing.T) {
d := t.TempDir()
tokens = state{
filename: filepath.Join(d, "test.jsonl"),
}
f, err := os.OpenFile(tokens.filename,
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600,
)
if err != nil {
t.Fatalf("Create: %v", err)
}
defer f.Close()
token, err := Parse("foo", nil)
if err == nil {
t.Errorf("Expected error, got %v", token)
}
token, err = Parse("foo", []map[string]interface{}{})
if err == nil {
t.Errorf("Expected error, got %v", token)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment