Skip to content

Commit 22c9886

Browse files
Allow credential mapping from dockercfg for canonical ports
1 parent 8cd3abf commit 22c9886

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

pkg/image/importer/credentials.go

+21-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ func (s *keyringCredentialStore) Basic(url *url.URL) (string, string) {
108108
}
109109

110110
func NewCredentialsForSecrets(secrets []kapiv1.Secret) *SecretCredentialStore {
111-
return &SecretCredentialStore{secrets: secrets}
111+
return &SecretCredentialStore{
112+
secrets: secrets,
113+
refreshTokenStore: &refreshTokenStore{},
114+
}
112115
}
113116

114117
func NewLazyCredentialsForSecrets(secretsFn func() ([]kapiv1.Secret, error)) *SecretCredentialStore {
@@ -165,7 +168,13 @@ func (s *SecretCredentialStore) init() credentialprovider.DockerKeyring {
165168

166169
func basicCredentialsFromKeyring(keyring credentialprovider.DockerKeyring, target *url.URL) (string, string) {
167170
// TODO: compare this logic to Docker authConfig in v2 configuration
168-
value := target.Host + target.Path
171+
var value string
172+
if len(target.Scheme) == 0 || target.Scheme == "https" {
173+
value = target.Host + target.Path
174+
} else {
175+
// only lookup credential for http that say they are for http
176+
value = target.String()
177+
}
169178

170179
// Lookup(...) expects an image (not a URL path).
171180
// The keyring strips /v1/ and /v2/ version prefixes,
@@ -188,6 +197,16 @@ func basicCredentialsFromKeyring(keyring credentialprovider.DockerKeyring, targe
188197
glog.V(5).Infof("Being asked for %s, trying %s for legacy behavior", target, "docker.io")
189198
return basicCredentialsFromKeyring(keyring, &url.URL{Host: "docker.io"})
190199
}
200+
201+
// try removing the canonical ports for the given requests
202+
if (strings.HasSuffix(target.Host, ":443") && target.Scheme == "https") ||
203+
(strings.HasSuffix(target.Host, ":80") && target.Scheme == "http") {
204+
host := strings.SplitN(target.Host, ":", 2)[0]
205+
glog.V(5).Infof("Being asked for %s, trying %s without port", target, host)
206+
207+
return basicCredentialsFromKeyring(keyring, &url.URL{Scheme: target.Scheme, Host: host, Path: target.Path})
208+
}
209+
191210
glog.V(5).Infof("Unable to find a secret to match %s (%s)", target, value)
192211
return "", ""
193212
}

pkg/image/importer/credentials_test.go

+55-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
kapiv1 "k8s.io/kubernetes/pkg/api/v1"
1212
"k8s.io/kubernetes/pkg/credentialprovider"
1313

14-
"github.com/golang/glog"
1514
_ "github.com/openshift/origin/pkg/api/install"
1615
)
1716

@@ -29,7 +28,7 @@ func TestCredentialsForSecrets(t *testing.T) {
2928
for i, secret := range secrets.Items {
3029
err := kapiv1.Convert_api_Secret_To_v1_Secret(&secret, &secretsv1[i], nil)
3130
if err != nil {
32-
glog.V(2).Infof("Unable to make the Docker keyring for %s/%s secret: %v", secret.Name, secret.Namespace, err)
31+
t.Logf("Unable to make the Docker keyring for %s/%s secret: %v", secret.Name, secret.Namespace, err)
3332
continue
3433
}
3534
}
@@ -70,3 +69,57 @@ func TestBasicCredentials(t *testing.T) {
7069
t.Fatalf("unexpected response: %s %s", u, p)
7170
}
7271
}
72+
73+
func Test_basicCredentialsFromKeyring(t *testing.T) {
74+
fn := func(host string, entry credentialprovider.DockerConfigEntry) credentialprovider.DockerKeyring {
75+
k := &credentialprovider.BasicDockerKeyring{}
76+
k.Add(map[string]credentialprovider.DockerConfigEntry{host: entry})
77+
return k
78+
}
79+
def := credentialprovider.DockerConfigEntry{
80+
Username: "local_user",
81+
Password: "local_pass",
82+
}
83+
type args struct {
84+
keyring credentialprovider.DockerKeyring
85+
target *url.URL
86+
}
87+
tests := []struct {
88+
name string
89+
args args
90+
user string
91+
password string
92+
}{
93+
{name: "exact", args: args{keyring: fn("localhost", def), target: &url.URL{Host: "localhost"}}, user: def.Username, password: def.Password},
94+
{name: "https scheme", args: args{keyring: fn("localhost", def), target: &url.URL{Scheme: "https", Host: "localhost"}}, user: def.Username, password: def.Password},
95+
{name: "canonical https", args: args{keyring: fn("localhost", def), target: &url.URL{Scheme: "https", Host: "localhost:443"}}, user: def.Username, password: def.Password},
96+
{name: "only https", args: args{keyring: fn("https://localhost", def), target: &url.URL{Host: "localhost"}}, user: def.Username, password: def.Password},
97+
{name: "only https scheme", args: args{keyring: fn("https://localhost", def), target: &url.URL{Scheme: "https", Host: "localhost"}}, user: def.Username, password: def.Password},
98+
{name: "mismatched scheme - http", args: args{keyring: fn("http://localhost", def), target: &url.URL{Scheme: "https", Host: "localhost"}}, user: def.Username, password: def.Password},
99+
100+
// this is not allowed by the credential keyring, but should be
101+
{name: "exact http", args: args{keyring: fn("http://localhost", def), target: &url.URL{Scheme: "http", Host: "localhost:80"}}, user: "", password: ""},
102+
{name: "keyring canonical https", args: args{keyring: fn("localhost:443", def), target: &url.URL{Scheme: "https", Host: "localhost"}}, user: "", password: ""},
103+
104+
// these should not be allowed
105+
{name: "host is for port 80 only", args: args{keyring: fn("localhost:80", def), target: &url.URL{Host: "localhost"}}, user: "", password: ""},
106+
{name: "host is for port 443 only", args: args{keyring: fn("localhost:443", def), target: &url.URL{Host: "localhost"}}, user: "", password: ""},
107+
{name: "don't assume port 80 in keyring is https", args: args{keyring: fn("localhost:80", def), target: &url.URL{Scheme: "http", Host: "localhost"}}, user: "", password: ""},
108+
{name: "canonical http", args: args{keyring: fn("localhost", def), target: &url.URL{Scheme: "http", Host: "localhost:80"}}, user: "", password: ""},
109+
{name: "http scheme", args: args{keyring: fn("localhost", def), target: &url.URL{Scheme: "http", Host: "localhost"}}, user: "", password: ""},
110+
{name: "https not canonical", args: args{keyring: fn("localhost", def), target: &url.URL{Scheme: "https", Host: "localhost:80"}}, user: "", password: ""},
111+
{name: "http not canonical", args: args{keyring: fn("localhost", def), target: &url.URL{Scheme: "http", Host: "localhost:443"}}, user: "", password: ""},
112+
{name: "mismatched scheme", args: args{keyring: fn("https://localhost", def), target: &url.URL{Scheme: "http", Host: "localhost"}}, user: "", password: ""},
113+
}
114+
for _, tt := range tests {
115+
t.Run(tt.name, func(t *testing.T) {
116+
user, password := basicCredentialsFromKeyring(tt.args.keyring, tt.args.target)
117+
if user != tt.user {
118+
t.Errorf("basicCredentialsFromKeyring() user = %v, actual = %v", user, tt.user)
119+
}
120+
if password != tt.password {
121+
t.Errorf("basicCredentialsFromKeyring() password = %v, actual = %v", password, tt.password)
122+
}
123+
})
124+
}
125+
}

0 commit comments

Comments
 (0)