aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Steuck <greg@nest.cx>2021-07-04 06:35:26 -0700
committerDmitry Vyukov <dvyukov@google.com>2021-07-14 07:16:41 +0200
commit8a2d0342e072b3bdbc232f5158f421a3b96cc2a0 (patch)
tree6d9ed57fb4a006e351934c6fc7179b54c158f428
parent116439eed7dad478f73e1fb883285609926eafc9 (diff)
dashboard/app: parse JWT into a separate JSON struct
Between JSON type choices and Go struct embedding syntax noise, relying on field duplication seems the least ugly option.
-rw-r--r--dashboard/app/auth.go34
-rw-r--r--dashboard/app/auth_test.go17
2 files changed, 36 insertions, 15 deletions
diff --git a/dashboard/app/auth.go b/dashboard/app/auth.go
index c356ad543..b096ebf38 100644
--- a/dashboard/app/auth.go
+++ b/dashboard/app/auth.go
@@ -32,6 +32,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "strconv"
"strings"
"time"
@@ -57,10 +58,20 @@ func mkAuthEndpoint(u string) authEndpoint {
return authEndpoint{url: u}
}
+// The JSON representaion of JWT claims.
+type jwtClaimsParse struct {
+ Subject string `json:"sub"`
+ Audience string `json:"aud"`
+ // The field in the JSON is a string but contains a UNIX time.
+ Expiration string `json:"exp"`
+}
+
+// The typed representation of JWT claims.
type jwtClaims struct {
- Subject string `json:"sub"`
- Expiration float64 `json:"exp"`
- Audience string `json:"aud"`
+ Subject string
+ Audience string
+ // The app uses the typed value.
+ Expiration time.Time
}
func (auth *authEndpoint) queryTokenInfo(tokenValue string) (*jwtClaims, error) {
@@ -73,11 +84,20 @@ func (auth *authEndpoint) queryTokenInfo(tokenValue string) (*jwtClaims, error)
if err != nil {
return nil, err
}
- claims := new(jwtClaims)
+ claims := new(jwtClaimsParse)
if err = json.Unmarshal(body, claims); err != nil {
return nil, err
}
- return claims, nil
+ expInt, err := strconv.ParseInt(claims.Expiration, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ r := jwtClaims{
+ Subject: claims.Subject,
+ Audience: claims.Audience,
+ Expiration: time.Unix(expInt, 0),
+ }
+ return &r, nil
}
// Returns the verified subject value based on the provided header
@@ -96,10 +116,10 @@ func (auth *authEndpoint) determineAuthSubj(authHeader []string) (string, error)
return "", err
}
if claims.Audience != dashapi.DashboardAudience {
- err := fmt.Errorf("Unexpected audience %v", claims.Audience)
+ err := fmt.Errorf("Unexpected audience %v %v", claims.Audience, claims)
return "", err
}
- if claims.Expiration < float64(time.Now().Unix()) {
+ if claims.Expiration.Before(time.Now()) {
err := fmt.Errorf("Token past expiration %v", claims.Expiration)
return "", err
}
diff --git a/dashboard/app/auth_test.go b/dashboard/app/auth_test.go
index 6b68f61a1..02d7ad9fc 100644
--- a/dashboard/app/auth_test.go
+++ b/dashboard/app/auth_test.go
@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
+ "fmt"
"github.com/google/syzkaller/dashboard/dashapi"
"net/http"
"net/http/httptest"
@@ -10,13 +11,13 @@ import (
"time"
)
-func dayFromNow() float64 {
- return float64(time.Now().AddDate(0, 0, 1).Unix())
-}
-
func reponseFor(t *testing.T, claims jwtClaims) (*httptest.Server, authEndpoint) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- bytes, err := json.Marshal(claims)
+ bytes, err := json.Marshal(jwtClaimsParse{
+ Subject: claims.Subject,
+ Audience: claims.Audience,
+ Expiration: fmt.Sprint(claims.Expiration.Unix()),
+ })
if err != nil {
t.Fatalf("Marshal %v", err)
}
@@ -30,8 +31,8 @@ func TestBearerValid(t *testing.T) {
magic := "ValidSubj"
ts, dut := reponseFor(t, jwtClaims{
Subject: magic,
- Expiration: dayFromNow(),
Audience: dashapi.DashboardAudience,
+ Expiration: time.Now().AddDate(0, 0, 1),
})
defer ts.Close()
@@ -47,7 +48,7 @@ func TestBearerValid(t *testing.T) {
func TestBearerWrongAudience(t *testing.T) {
ts, dut := reponseFor(t, jwtClaims{
Subject: "irrelevant",
- Expiration: dayFromNow(),
+ Expiration: time.Now().AddDate(0, 0, 1),
Audience: "junk",
})
defer ts.Close()
@@ -61,7 +62,7 @@ func TestBearerWrongAudience(t *testing.T) {
func TestBearerExpired(t *testing.T) {
ts, dut := reponseFor(t, jwtClaims{
Subject: "irrelevant",
- Expiration: -1234,
+ Expiration: time.Now().AddDate(0, 0, -1),
Audience: dashapi.DashboardAudience,
})
defer ts.Close()