aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dashboard/dashapi/dashapi.go34
-rw-r--r--pkg/auth/auth.go4
-rw-r--r--pkg/auth/auth_test.go6
-rw-r--r--pkg/auth/jwt.go (renamed from dashboard/dashapi/jwt.go)48
4 files changed, 47 insertions, 45 deletions
diff --git a/dashboard/dashapi/dashapi.go b/dashboard/dashapi/dashapi.go
index d36adaa68..b583f893d 100644
--- a/dashboard/dashapi/dashapi.go
+++ b/dashboard/dashapi/dashapi.go
@@ -17,7 +17,10 @@ import (
"net/url"
"reflect"
"strings"
+ "sync"
"time"
+
+ "github.com/google/syzkaller/pkg/auth"
)
type Dashboard struct {
@@ -45,11 +48,11 @@ type (
func NewCustom(client, addr, key string, ctor RequestCtor, doer RequestDoer,
logger RequestLogger, errorHandler func(error)) (*Dashboard, error) {
if key == "" {
- token, err := retrieveJwtToken(ctor, doer)
+ token, err := auth.RetrieveJwtToken(ctor, doer)
if err != nil {
return nil, err
}
- doer = atachJwtToken(ctor, doer, token)
+ doer = attachJwtToken(ctor, doer, token)
}
return &Dashboard{
Client: client,
@@ -62,6 +65,29 @@ func NewCustom(client, addr, key string, ctor RequestCtor, doer RequestDoer,
}, nil
}
+// Augments the given doer with an authorization header carrying the
+// given token. The token gets refreshed when it becomes stale.
+func attachJwtToken(ctor RequestCtor, doer RequestDoer, token *auth.ExpiringToken) RequestDoer {
+ lock := sync.Mutex{}
+ return func(req *http.Request) (*http.Response, error) {
+ lock.Lock()
+ if token.Expiration.Before(time.Now()) {
+ // Keeping the lock while making http request is dubious, but
+ // making multiple concurrent requests is not any better.
+ t, err := auth.RetrieveJwtToken(ctor, doer)
+ if err != nil {
+ // Can't get a new token, so returning the error preemptively.
+ lock.Unlock()
+ return nil, err
+ }
+ *token = *t
+ }
+ req.Header.Add("Authorization", "Bearer "+token.Token)
+ lock.Unlock()
+ return doer(req)
+ }
+}
+
// Build describes all aspects of a kernel build.
type Build struct {
Manager string
@@ -570,10 +596,6 @@ const (
ReportBisectFix // Fix bisection result for an already reported bug.
)
-const (
- DashboardAudience = "https://syzkaller.appspot.com/api"
-)
-
func (dash *Dashboard) Query(method string, req, reply interface{}) error {
if dash.logger != nil {
dash.logger("API(%v): %#v", method, req)
diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go
index bd542bc32..c662218ea 100644
--- a/pkg/auth/auth.go
+++ b/pkg/auth/auth.go
@@ -35,8 +35,6 @@ import (
"strconv"
"strings"
"time"
-
- "github.com/google/syzkaller/dashboard/dashapi"
)
const (
@@ -117,7 +115,7 @@ func (auth *Endpoint) DetermineAuthSubj(now time.Time, authHeader []string) (str
if err != nil {
return "", err
}
- if claims.Audience != dashapi.DashboardAudience {
+ if claims.Audience != DashboardAudience {
err := fmt.Errorf("unexpected audience %v %v", claims.Audience, claims)
return "", err
}
diff --git a/pkg/auth/auth_test.go b/pkg/auth/auth_test.go
index 13a9c5749..7e0a5184f 100644
--- a/pkg/auth/auth_test.go
+++ b/pkg/auth/auth_test.go
@@ -11,8 +11,6 @@ import (
"strings"
"testing"
"time"
-
- "github.com/google/syzkaller/dashboard/dashapi"
)
func reponseFor(t *testing.T, claims jwtClaims) (*httptest.Server, Endpoint) {
@@ -36,7 +34,7 @@ func TestBearerValid(t *testing.T) {
magic := "ValidSubj"
ts, dut := reponseFor(t, jwtClaims{
Subject: magic,
- Audience: dashapi.DashboardAudience,
+ Audience: DashboardAudience,
Expiration: tm.AddDate(0, 0, 1),
})
defer ts.Close()
@@ -70,7 +68,7 @@ func TestBearerExpired(t *testing.T) {
ts, dut := reponseFor(t, jwtClaims{
Subject: "irrelevant",
Expiration: tm.AddDate(0, 0, -1),
- Audience: dashapi.DashboardAudience,
+ Audience: DashboardAudience,
})
defer ts.Close()
diff --git a/dashboard/dashapi/jwt.go b/pkg/auth/jwt.go
index 7c0cd25ca..680c16281 100644
--- a/dashboard/dashapi/jwt.go
+++ b/pkg/auth/jwt.go
@@ -1,22 +1,26 @@
// Copyright 2021 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
-package dashapi
+package auth
import (
"encoding/base64"
"encoding/json"
"fmt"
+ "io"
"io/ioutil"
"net/http"
"strings"
- "sync"
"time"
)
-type expiringToken struct {
- token string
- expiration time.Time
+const (
+ DashboardAudience = "https://syzkaller.appspot.com/api"
+)
+
+type ExpiringToken struct {
+ Token string
+ Expiration time.Time
}
// Returns the unverified expiration value from the given JWT token.
@@ -39,9 +43,12 @@ func extractJwtExpiration(token string) (time.Time, error) {
return time.Unix(claims.Expiration, 0), nil
}
-// Queries the metadata server and returns the bearer token of the service account.
-// The token is scoped for the official dashboard.
-func retrieveJwtToken(ctor RequestCtor, doer RequestDoer) (*expiringToken, error) {
+// Queries the metadata server and returns the bearer token of the
+// service account. The token is scoped for the official dashboard.
+// The types of ctor and doer are the same as in http.NewRequest and
+// http.DefaultClient.Do.
+func RetrieveJwtToken(ctor func(method, url string, body io.Reader) (*http.Request, error),
+ doer func(req *http.Request) (*http.Response, error)) (*ExpiringToken, error) {
const v1meta = "http://metadata.google.internal/computeMetadata/v1"
req, err := ctor("GET", v1meta+"/instance/service-accounts/default/identity?audience="+DashboardAudience, nil)
if err != nil {
@@ -65,28 +72,5 @@ func retrieveJwtToken(ctor RequestCtor, doer RequestDoer) (*expiringToken, error
if err != nil {
return nil, err
}
- return &expiringToken{token, expiration}, nil
-}
-
-// Augments the given doer with an authorization header carrying the
-// given token. The token gets refreshed when it becomes stale.
-func atachJwtToken(ctor RequestCtor, doer RequestDoer, token *expiringToken) RequestDoer {
- lock := sync.Mutex{}
- return func(req *http.Request) (*http.Response, error) {
- lock.Lock()
- if token.expiration.Before(time.Now()) {
- // Keeping the lock while making http request is dubious, but
- // making multiple concurrent requests is not any better.
- t, err := retrieveJwtToken(ctor, doer)
- if err != nil {
- // Can't get a new token, so returning the error preemptively.
- lock.Unlock()
- return nil, err
- }
- *token = *t
- }
- req.Header.Add("Authorization", "Bearer "+token.token)
- lock.Unlock()
- return doer(req)
- }
+ return &ExpiringToken{token, expiration}, nil
}