1
0
mirror of https://github.com/regclient/regclient.git synced 2025-04-18 22:44:00 +03:00

Fix: Allow authentication with a token

This fixes a regression caused by PR #893.

Signed-off-by: Brandon Mitchell <git@bmitch.net>
This commit is contained in:
Brandon Mitchell 2025-02-12 15:59:00 -05:00
parent 2dc14baefb
commit 0cd8674a8b
No known key found for this signature in database
GPG Key ID: 6E0FF28C767A8BEE
2 changed files with 80 additions and 8 deletions

View File

@ -624,9 +624,10 @@ func (b *bearerHandler) GenerateAuth() (string, error) {
return fmt.Sprintf("Bearer %s", b.token.Token), nil
}
// attempt to post if a refresh token is available
if b.token.RefreshToken != "" {
if err := b.tryPost(); err == nil {
// attempt to post if a refresh token is available or token auth is being used
cred := b.credsFn(b.host)
if b.token.RefreshToken != "" || cred.Token != "" {
if err := b.tryPost(cred); err == nil {
return fmt.Sprintf("Bearer %s", b.token.Token), nil
} else if err != ErrUnauthorized {
return "", fmt.Errorf("failed to request auth token (post): %w%.0w", err, errs.ErrHTTPUnauthorized)
@ -634,7 +635,7 @@ func (b *bearerHandler) GenerateAuth() (string, error) {
}
// attempt a get (with basic auth if user/pass available)
if err := b.tryGet(); err == nil {
if err := b.tryGet(cred); err == nil {
return fmt.Sprintf("Bearer %s", b.token.Token), nil
} else if err != ErrUnauthorized {
return "", fmt.Errorf("failed to request auth token (get): %w%.0w", err, errs.ErrHTTPUnauthorized)
@ -655,8 +656,7 @@ func (b *bearerHandler) isExpired() bool {
}
// tryGet requests a new token with a GET request
func (b *bearerHandler) tryGet() error {
cred := b.credsFn(b.host)
func (b *bearerHandler) tryGet(cred Cred) error {
req, err := http.NewRequest("GET", b.realm, nil)
if err != nil {
return err
@ -691,8 +691,7 @@ func (b *bearerHandler) tryGet() error {
}
// tryPost requests a new token via a POST request
func (b *bearerHandler) tryPost() error {
cred := b.credsFn(b.host)
func (b *bearerHandler) tryPost(cred Cred) error {
form := url.Values{}
if len(b.scopes) > 0 {
form.Set("scope", strings.Join(b.scopes, " "))

View File

@ -4,6 +4,7 @@ import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"net/http"
@ -653,3 +654,75 @@ func TestBearer(t *testing.T) {
t.Errorf("token5 (rerun) is already expired")
}
}
// TestBearerToken verifies a login with a token in the credential with a bearer request goes to POST.
func TestBearerToken(t *testing.T) {
t.Parallel()
useragent := "regclient/test"
user := "user"
token := "testtoken"
tokenResp, _ := json.Marshal(bearerToken{
Token: token,
ExpiresIn: 900,
IssuedAt: time.Now(),
Scope: "repository:reponame:pull",
RefreshToken: token,
})
tokenForm := url.Values{}
tokenForm.Set("scope", "repository:reponame:pull")
tokenForm.Set("service", "test")
tokenForm.Set("client_id", useragent)
tokenForm.Set("grant_type", "refresh_token")
tokenForm.Set("refresh_token", token)
tokenBody := tokenForm.Encode()
rrs := []reqresp.ReqResp{
{
ReqEntry: reqresp.ReqEntry{
Name: "req token",
Method: "POST",
Path: "/tokens",
Body: []byte(tokenBody),
},
RespEntry: reqresp.RespEntry{
Status: 200,
Body: tokenResp,
},
},
}
ts := httptest.NewServer(reqresp.NewHandler(t, rrs))
defer ts.Close()
tsURL, _ := url.Parse(ts.URL)
tsHost := tsURL.Host
bearer := NewBearerHandler(&http.Client{}, useragent, tsHost,
func(h string) Cred { return Cred{User: user, Token: token} },
slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{})),
).(*bearerHandler)
// handle token1, verify expired token gets current time and isn't expired
err := bearer.AddScope("repository:reponame:pull")
if err != nil {
t.Errorf("failed adding scope: %v", err)
}
c, err := parseAuthHeader(
`Bearer realm="` + tsURL.String() +
`/tokens",service="test"` +
`,scope="repository:reponame:pull"`)
if err != nil {
t.Errorf("failed on parse challenge: %v", err)
}
err = bearer.ProcessChallenge(c[0])
if err != nil {
t.Errorf("failed on response to token: %v", err)
}
resp, err := bearer.GenerateAuth()
if err != nil {
t.Errorf("failed to generate auth response: %v", err)
}
bearerResp := fmt.Sprintf("Bearer %s", token)
if resp != bearerResp {
t.Errorf("token1 is invalid, expected %s, received %s", "Bearer token1", resp)
}
if bearer.isExpired() {
t.Errorf("token1 is already expired")
}
}