Skip to content

Commit f58ba12

Browse files
committed
fix(auth): SigV4 sends derived ApiKey for uploads; auth verify uses gated endpoint
- auth.GetAuthHeader now returns the derived ApiKey (ApiKey <org>:<hmac>) for SigV4 instead of an empty header, and the upload client uses it directly (dropping the fragile cross-service JWT exchange). - 'auth verify' now validates against an authenticated VDB endpoint (same as login) instead of /uploads/verify, which is served by a different service.
1 parent 1d5340a commit f58ba12

4 files changed

Lines changed: 27 additions & 26 deletions

File tree

cmd/auth.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -602,9 +602,9 @@ func runAuthVerify(cmd *cobra.Command) error {
602602
progress.Update(1, fmt.Sprintf("Loaded credentials for org %s", creds.OrgID))
603603

604604
progress.SetStage("Verifying credentials with Vulnetix API")
605-
client := upload.NewClient(verifyBaseURL, creds)
606-
result, err := client.VerifyAuth()
607-
if err != nil {
605+
// Validate against an authenticated VDB endpoint (same path as login), not
606+
// the /uploads/* service.
607+
if err := testAuth(ctx, creds); err != nil {
608608
progress.Fail("verification failed")
609609
return fmt.Errorf("verification failed: %w", err)
610610
}
@@ -613,7 +613,7 @@ func runAuthVerify(cmd *cobra.Command) error {
613613

614614
ctx.Logger.Info(display.CheckMark(t) + " Authentication verified successfully")
615615
ctx.Logger.Result(display.KeyValue(t, []display.KVPair{
616-
{Key: "Organization", Value: result.OrgID},
616+
{Key: "Organization", Value: creds.OrgID},
617617
}))
618618
return nil
619619
}

internal/upload/client.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ type Client struct {
5151
HTTPClient *http.Client
5252
GitHubContext *GitHubActionsContext
5353
CliEnv *vdb.CliEnv
54-
55-
// sigv4Client is a lazily-created vdb client used only to perform the
56-
// SigV4 -> Bearer token exchange (GetAuthHeader returns "" for SigV4).
57-
sigv4Client *vdb.Client
5854
}
5955

6056
// ProgressFunc reports upload stage progress against a fixed per-file goal.
@@ -430,17 +426,8 @@ func (c *Client) addAuth(req *http.Request) {
430426
if c.Creds == nil {
431427
return
432428
}
433-
// SigV4 needs a token exchange (auth.GetAuthHeader returns "" for it). The
434-
// vdb client performs the SigV4 -> Bearer exchange and caches the token.
435-
if c.Creds.Method == auth.SigV4 {
436-
if c.sigv4Client == nil {
437-
c.sigv4Client = vdb.NewClientFromCredentials(c.Creds)
438-
}
439-
if tok, err := c.sigv4Client.GetToken(); err == nil && tok != "" {
440-
req.Header.Set("Authorization", "Bearer "+tok)
441-
}
442-
return
443-
}
429+
// GetAuthHeader handles all methods: Token -> Bearer, DirectAPIKey/SigV4 ->
430+
// ApiKey <org>:<hmac>. The /uploads/* endpoints (vdb-site) accept ApiKey.
444431
if header := auth.GetAuthHeader(c.Creds); header != "" {
445432
req.Header.Set("Authorization", header)
446433
}

pkg/auth/auth.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package auth
22

3-
import "fmt"
3+
import (
4+
"crypto/hmac"
5+
"crypto/sha256"
6+
"encoding/hex"
7+
"fmt"
8+
)
49

510
// AuthMethod represents the authentication method to use
611
type AuthMethod string
@@ -80,9 +85,11 @@ func GetAuthHeader(creds *Credentials) string {
8085
case DirectAPIKey:
8186
return fmt.Sprintf("ApiKey %s:%s", creds.OrgID, creds.APIKey)
8287
case SigV4:
83-
// SigV4 uses Bearer tokens obtained from the token exchange flow.
84-
// The caller must obtain the token separately and use it as Bearer.
85-
return ""
88+
// The upload endpoints (vdb-site) accept the derived ApiKey; send that
89+
// instead of exchanging a cross-service JWT. ApiKey = HMAC-SHA256(secret, org).
90+
mac := hmac.New(sha256.New, []byte(creds.Secret))
91+
mac.Write([]byte(creds.OrgID))
92+
return fmt.Sprintf("ApiKey %s:%s", creds.OrgID, hex.EncodeToString(mac.Sum(nil)))
8693
default:
8794
return ""
8895
}

pkg/auth/auth_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package auth
22

33
import (
4+
"crypto/hmac"
5+
"crypto/sha256"
6+
"encoding/hex"
47
"testing"
58
)
69

@@ -88,9 +91,13 @@ func TestGetAuthHeader_SigV4(t *testing.T) {
8891
Secret: "secret",
8992
Method: SigV4,
9093
}
91-
header := GetAuthHeader(creds)
92-
if header != "" {
93-
t.Errorf("expected empty header for SigV4, got %q", header)
94+
// SigV4 sends the derived ApiKey for endpoints that accept ApiKey (uploads):
95+
// ApiKey <org>:<HMAC-SHA256(secret, org)>.
96+
mac := hmac.New(sha256.New, []byte("secret"))
97+
mac.Write([]byte("test-org"))
98+
want := "ApiKey test-org:" + hex.EncodeToString(mac.Sum(nil))
99+
if header := GetAuthHeader(creds); header != want {
100+
t.Errorf("expected %q for SigV4, got %q", want, header)
94101
}
95102
}
96103

0 commit comments

Comments
 (0)