distribution/registry/proxy/proxyauth_exec_test.go
Chun-Hung Hsiao eed9400d26
feat: support custom exec-based credential helper in proxy mode
This change allows users to run the registry as a pull-through cache
that can use a credential helper to authenticate against the upstream
registry.

Signed-off-by: Chun-Hung Hsiao <chhsiao@google.com>
2024-08-16 19:42:51 -07:00

176 lines
4.1 KiB
Go

package proxy
import (
"fmt"
"io"
"net/url"
"testing"
"time"
"github.com/docker/docker-credential-helpers/client"
credspkg "github.com/docker/docker-credential-helpers/credentials"
)
type testHelper struct {
username string
secret string
err error
}
func (h *testHelper) Output() ([]byte, error) {
return []byte(fmt.Sprintf(`{"Username":%q,"Secret":%q}`, h.username, h.secret)), h.err
}
func (h *testHelper) Input(in io.Reader) {
}
var _ client.Program = (*testHelper)(nil)
func TestExecAuth(t *testing.T) {
ptrDuration := func(t time.Duration) *time.Duration { return &t }
for _, tc := range []struct {
name string
helper client.ProgramFunc
lifetime *time.Duration
currCreds *credspkg.Credentials
currExpiry time.Time
wantUsername string
wantPassword string
wantExpiry time.Time
}{{
name: "first auth without lifetime",
helper: func(...string) client.Program {
return &testHelper{
username: "user",
secret: "nextpass",
}
},
wantUsername: "user",
wantPassword: "nextpass",
}, {
name: "first auth with zero lifetime",
helper: func(...string) client.Program {
return &testHelper{
username: "user",
secret: "nextpass",
}
},
lifetime: ptrDuration(0),
wantUsername: "user",
wantPassword: "nextpass",
}, {
name: "first auth with lifetime",
helper: func(...string) client.Program {
return &testHelper{
username: "user",
secret: "nextpass",
}
},
lifetime: ptrDuration(time.Hour),
wantUsername: "user",
wantPassword: "nextpass",
wantExpiry: time.Now().Add(time.Hour),
}, {
name: "re-auth without lifetime",
helper: func(...string) client.Program {
return &testHelper{
username: "user",
secret: "nextpass",
}
},
currCreds: &credspkg.Credentials{
Username: "user",
Secret: "currpass",
},
wantUsername: "user",
wantPassword: "currpass",
}, {
name: "re-auth with zero lifetime",
helper: func(...string) client.Program {
return &testHelper{
username: "user",
secret: "nextpass",
}
},
lifetime: ptrDuration(0),
currCreds: &credspkg.Credentials{
Username: "user",
Secret: "currpass",
},
wantUsername: "user",
wantPassword: "nextpass",
}, {
name: "re-auth when not expired",
helper: func(...string) client.Program {
return &testHelper{
username: "user",
secret: "nextpass",
}
},
lifetime: ptrDuration(time.Hour),
currCreds: &credspkg.Credentials{
Username: "user",
Secret: "currpass",
},
currExpiry: time.Now().Add(time.Minute),
wantUsername: "user",
wantPassword: "currpass",
wantExpiry: time.Now().Add(time.Minute),
}, {
name: "re-auth when expired",
helper: func(...string) client.Program {
return &testHelper{
username: "user",
secret: "nextpass",
}
},
lifetime: ptrDuration(time.Hour),
currCreds: &credspkg.Credentials{
Username: "user",
Secret: "currpass",
},
currExpiry: time.Now().Add(-1),
wantUsername: "user",
wantPassword: "nextpass",
wantExpiry: time.Now().Add(time.Hour),
}, {
name: "exec error",
helper: func(...string) client.Program {
return &testHelper{
err: fmt.Errorf("exec error"),
}
},
lifetime: ptrDuration(time.Hour),
currCreds: &credspkg.Credentials{
Username: "user",
Secret: "currpass",
},
currExpiry: time.Now().Add(-1),
wantUsername: "",
wantPassword: "",
wantExpiry: time.Now().Add(-1),
}} {
t.Run(tc.name, func(t *testing.T) {
cs := &execCredentials{
helper: tc.helper,
lifetime: tc.lifetime,
creds: tc.currCreds,
expiry: tc.currExpiry,
}
url := &url.URL{
Scheme: "https",
Host: "example.com",
}
user, pass := cs.Basic(url)
if user != tc.wantUsername || pass != tc.wantPassword {
t.Errorf("execCredentials.Basic(%q) = (%q, %q), want (%q, %q)", url, user, pass, tc.wantUsername, tc.wantPassword)
}
// All tests should finish within seconds, so the time error should be less than a minute.
if cs.expiry.Sub(tc.wantExpiry).Abs() > time.Minute {
t.Errorf("execCredentials.expiry = %v, want %v", cs.expiry, tc.wantExpiry)
}
})
}
}