Skip to content

Commit 7fc3c96

Browse files
committed
Support authentication from Docker daemon to private docker registry.
1 parent 4df618a commit 7fc3c96

File tree

22 files changed

+922
-12
lines changed

22 files changed

+922
-12
lines changed

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
2525
import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;
2626
import org.springframework.boot.buildpack.platform.docker.UpdateListener;
27+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration;
2728
import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;
2829
import org.springframework.boot.buildpack.platform.docker.type.Image;
2930
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
@@ -48,8 +49,16 @@ public Builder() {
4849
this(BuildLog.toSystemOut());
4950
}
5051

52+
public Builder(DockerConfiguration dockerConfiguration) {
53+
this(BuildLog.toSystemOut(), dockerConfiguration);
54+
}
55+
5156
public Builder(BuildLog log) {
52-
this(log, new DockerApi());
57+
this(log, new DockerApi(new DockerConfiguration()));
58+
}
59+
60+
public Builder(BuildLog log, DockerConfiguration dockerConfiguration) {
61+
this(log, new DockerApi(dockerConfiguration));
5362
}
5463

5564
Builder(BuildLog log, DockerApi docker) {

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@
2424
import java.util.Collections;
2525
import java.util.List;
2626

27+
import org.apache.http.Header;
2728
import org.apache.http.client.utils.URIBuilder;
29+
import org.apache.http.message.BasicHeader;
2830

31+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration;
32+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration;
2933
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport;
3034
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;
3135
import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;
@@ -68,7 +72,15 @@ public class DockerApi {
6872
* Create a new {@link DockerApi} instance.
6973
*/
7074
public DockerApi() {
71-
this(HttpTransport.create());
75+
this(new DockerConfiguration());
76+
}
77+
78+
/**
79+
* Create a new {@link DockerApi} instance.
80+
* @param dockerConfiguration the Docker configuration options.
81+
*/
82+
public DockerApi(DockerConfiguration dockerConfiguration) {
83+
this(HttpTransport.create(createDockerEngineAuthenticationHeaders(dockerConfiguration)));
7284
}
7385

7486
/**
@@ -84,6 +96,22 @@ public DockerApi() {
8496
this.volume = new VolumeApi();
8597
}
8698

99+
static Collection<Header> createDockerEngineAuthenticationHeaders(DockerConfiguration dockerConfiguration) {
100+
Assert.notNull(dockerConfiguration, "Docker configuration must not be null");
101+
102+
DockerRegistryConfiguration dockerRegistryConfiguration = dockerConfiguration.getDockerRegistryConfiguration();
103+
if (dockerRegistryConfiguration == null) {
104+
return Collections.emptyList();
105+
}
106+
107+
String dockerRegistryAuthToken = dockerRegistryConfiguration.createDockerRegistryAuthToken();
108+
if (StringUtils.isEmpty(dockerRegistryAuthToken)) {
109+
return Collections.emptyList();
110+
}
111+
112+
return Arrays.asList(new BasicHeader("X-Registry-Auth", dockerRegistryAuthToken));
113+
}
114+
87115
private HttpTransport http() {
88116
return this.http;
89117
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.buildpack.platform.docker.configuration;
18+
19+
/**
20+
* Docker configuration options.
21+
*
22+
* @author Wei Jiang
23+
* @since 2.4.0
24+
*/
25+
public class DockerConfiguration {
26+
27+
/**
28+
* The docker registry configuration.
29+
*/
30+
private DockerRegistryConfiguration dockerRegistryConfiguration;
31+
32+
public DockerConfiguration() {
33+
super();
34+
}
35+
36+
public DockerConfiguration(DockerRegistryConfiguration dockerRegistryConfiguration) {
37+
super();
38+
this.dockerRegistryConfiguration = dockerRegistryConfiguration;
39+
}
40+
41+
public DockerRegistryConfiguration getDockerRegistryConfiguration() {
42+
return this.dockerRegistryConfiguration;
43+
}
44+
45+
public void setDockerRegistryConfiguration(DockerRegistryConfiguration dockerRegistryConfiguration) {
46+
this.dockerRegistryConfiguration = dockerRegistryConfiguration;
47+
}
48+
49+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.buildpack.platform.docker.configuration;
18+
19+
import java.io.IOException;
20+
21+
import com.fasterxml.jackson.annotation.JsonIgnore;
22+
import com.fasterxml.jackson.annotation.JsonProperty;
23+
24+
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
25+
import org.springframework.util.Base64Utils;
26+
import org.springframework.util.StringUtils;
27+
28+
/**
29+
* Docker registry configuration options.
30+
*
31+
* @author Wei Jiang
32+
* @since 2.4.0
33+
*/
34+
public class DockerRegistryConfiguration {
35+
36+
/**
37+
* Docker registry server address.
38+
*/
39+
@JsonProperty("serveraddress")
40+
private String url;
41+
42+
/**
43+
* Docker registry authentication username.
44+
*/
45+
private String username;
46+
47+
/**
48+
* Docker registry authentication password.
49+
*/
50+
private String password;
51+
52+
/**
53+
* Docker registry authentication email.
54+
*/
55+
private String email;
56+
57+
/**
58+
* Docker registry authentication identity token.
59+
*/
60+
@JsonIgnore
61+
private String token;
62+
63+
public DockerRegistryConfiguration() {
64+
super();
65+
}
66+
67+
public DockerRegistryConfiguration(String url, String username, String password, String email, String token) {
68+
super();
69+
this.url = url;
70+
this.username = username;
71+
this.password = password;
72+
this.email = email;
73+
this.token = token;
74+
}
75+
76+
public String createDockerRegistryAuthToken() {
77+
if (!StringUtils.isEmpty(this.getToken())) {
78+
return this.getToken();
79+
}
80+
81+
try {
82+
return Base64Utils.encodeToString(SharedObjectMapper.get().writeValueAsBytes(this));
83+
}
84+
catch (IOException ex) {
85+
throw new IllegalStateException("create docker registry authentication token failed.", ex);
86+
}
87+
}
88+
89+
public String getUrl() {
90+
return this.url;
91+
}
92+
93+
public void setUrl(String url) {
94+
this.url = url;
95+
}
96+
97+
public String getUsername() {
98+
return this.username;
99+
}
100+
101+
public void setUsername(String username) {
102+
this.username = username;
103+
}
104+
105+
public String getPassword() {
106+
return this.password;
107+
}
108+
109+
public void setPassword(String password) {
110+
this.password = password;
111+
}
112+
113+
public String getEmail() {
114+
return this.email;
115+
}
116+
117+
public void setEmail(String email) {
118+
this.email = email;
119+
}
120+
121+
public String getToken() {
122+
return this.token;
123+
}
124+
125+
public void setToken(String token) {
126+
this.token = token;
127+
}
128+
129+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Docker configuration options.
19+
*/
20+
package org.springframework.boot.buildpack.platform.docker.configuration;

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
import java.io.InputStream;
2222
import java.io.OutputStream;
2323
import java.net.URI;
24+
import java.util.Collection;
25+
import java.util.Collections;
26+
27+
import org.apache.http.Header;
2428

2529
import org.springframework.boot.buildpack.platform.io.IOConsumer;
2630
import org.springframework.boot.buildpack.platform.system.Environment;
@@ -84,7 +88,17 @@ public interface HttpTransport {
8488
* @return a {@link HttpTransport} instance
8589
*/
8690
static HttpTransport create() {
87-
return create(Environment.SYSTEM);
91+
return create(Collections.emptyList());
92+
}
93+
94+
/**
95+
* Create the most suitable {@link HttpTransport} based on the
96+
* {@link Environment#SYSTEM system environment}.
97+
* @param dockerEngineAuthenticationHeaders authentication headerS for Docker engine.
98+
* @return a {@link HttpTransport} instance
99+
*/
100+
static HttpTransport create(Collection<Header> dockerEngineAuthenticationHeaders) {
101+
return create(Environment.SYSTEM, dockerEngineAuthenticationHeaders);
88102
}
89103

90104
/**
@@ -94,8 +108,21 @@ static HttpTransport create() {
94108
* @return a {@link HttpTransport} instance
95109
*/
96110
static HttpTransport create(Environment environment) {
97-
HttpTransport remote = RemoteHttpClientTransport.createIfPossible(environment);
98-
return (remote != null) ? remote : LocalHttpClientTransport.create(environment);
111+
return create(environment, Collections.emptyList());
112+
}
113+
114+
/**
115+
* Create the most suitable {@link HttpTransport} based on the given
116+
* {@link Environment}.
117+
* @param environment the source environment
118+
* @param dockerEngineAuthenticationHeaders authentication headerS for Docker engine.
119+
* @return a {@link HttpTransport} instance
120+
*/
121+
static HttpTransport create(Environment environment, Collection<Header> dockerEngineAuthenticationHeaders) {
122+
HttpTransport remote = RemoteHttpClientTransport.createIfPossible(environment,
123+
dockerEngineAuthenticationHeaders);
124+
return (remote != null) ? remote
125+
: LocalHttpClientTransport.create(environment, dockerEngineAuthenticationHeaders);
99126
}
100127

101128
/**

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
import java.net.InetSocketAddress;
2222
import java.net.Socket;
2323
import java.net.UnknownHostException;
24+
import java.util.Collection;
2425

2526
import com.sun.jna.Platform;
27+
import org.apache.http.Header;
2628
import org.apache.http.HttpHost;
2729
import org.apache.http.config.Registry;
2830
import org.apache.http.config.RegistryBuilder;
@@ -41,6 +43,7 @@
4143
import org.springframework.boot.buildpack.platform.socket.DomainSocket;
4244
import org.springframework.boot.buildpack.platform.socket.NamedPipeSocket;
4345
import org.springframework.boot.buildpack.platform.system.Environment;
46+
import org.springframework.util.CollectionUtils;
4447

4548
/**
4649
* {@link HttpClientTransport} that talks to local Docker.
@@ -60,10 +63,14 @@ private LocalHttpClientTransport(CloseableHttpClient client) {
6063
super(client, LOCAL_DOCKER_HOST);
6164
}
6265

63-
static LocalHttpClientTransport create(Environment environment) {
66+
static LocalHttpClientTransport create(Environment environment,
67+
Collection<Header> dockerEngineAuthenticationHeaders) {
6468
HttpClientBuilder builder = HttpClients.custom();
6569
builder.setConnectionManager(new LocalConnectionManager(socketFilePath(environment)));
6670
builder.setSchemePortResolver(new LocalSchemePortResolver());
71+
if (!CollectionUtils.isEmpty(dockerEngineAuthenticationHeaders)) {
72+
builder.setDefaultHeaders(dockerEngineAuthenticationHeaders);
73+
}
6774
return new LocalHttpClientTransport(builder.build());
6875
}
6976

0 commit comments

Comments
 (0)