1
Fork 0

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.
This commit is contained in:
Juliusz Chroboczek 2023-05-14 21:14:59 +02:00
parent dc8a78be32
commit 3c0dbf5e9b
4 changed files with 55 additions and 6 deletions

View File

@ -120,7 +120,7 @@ func toStringArray(a []interface{}) ([]string, bool) {
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) {
return getKey(t.Header, keys)
})

View File

@ -55,11 +55,14 @@ func SetStatefulFilename(filename string) {
tokens.modTime = time.Time{}
}
func getStateful(token string) (Token, error) {
func getStateful(token string) (*Stateful, error) {
tokens.mu.Lock()
defer tokens.mu.Unlock()
err := tokens.load()
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
if tokens.tokens == nil {

View File

@ -2,6 +2,7 @@ package token
import (
"errors"
"os"
)
var ErrUsernameRequired = errors.New("username required")
@ -11,9 +12,23 @@ type Token interface {
}
func Parse(token string, keys []map[string]interface{}) (Token, error) {
t, err := getStateful(token)
if err == nil && t != nil {
return t, nil
// both getStateful and parseJWT may return nil, which we
// shouldn't cast into an interface. Be very careful.
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)
}

31
token/token_test.go Normal file
View File

@ -0,0 +1,31 @@
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)
}
}