Skip to content

Commit 4535fa7

Browse files
authored
Merge pull request #675 from docker-client/__engine
Merge the docker-engine repo and remove the obsolete OkDockerClient
2 parents ede550c + e7ac36c commit 4535fa7

File tree

106 files changed

+3851
-48
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+3851
-48
lines changed

api-client/build.gradle.kts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import java.util.*
33

44
plugins {
55
id("java")
6+
id("groovy")
67
id("org.jetbrains.kotlin.jvm")
78
id("maven-publish")
89
id("signing")
@@ -76,9 +77,10 @@ dependencies {
7677
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
7778
implementation(libs.moshi)
7879
implementation(libs.okhttp)
79-
// implementation("com.squareup.okhttp3:logging-interceptor:[4.9,5)!!4.11.0")
80+
implementation("org.bouncycastle:bcpkix-jdk18on:1.82")
81+
implementation("org.apache.commons:commons-compress:1.28.0")
82+
// implementation("com.squareup.okhttp3:logging-interceptor:${libs.versions.okhttpVersionrange.get()}!!${libs.versions.okhttp.get()}")
8083
implementation("de.gesellix:docker-remote-api-model-1-41:2025-10-31T17-49-00")
81-
implementation("de.gesellix:docker-engine:2025-10-31T18-10-00")
8284
implementation("de.gesellix:docker-filesocket:2025-10-31T17-48-00")
8385

8486
implementation(libs.slf4j)
@@ -91,8 +93,11 @@ dependencies {
9193
testImplementation(libs.junitPlatformLauncher)
9294
testImplementation(libs.junitPlatformCommons)
9395

96+
testImplementation("org.spockframework:spock-core:2.3-groovy-4.0")
97+
testRuntimeOnly("net.bytebuddy:byte-buddy:1.17.8")
98+
9499
testImplementation("org.apache.commons:commons-compress:1.28.0")
95-
testImplementation("de.gesellix:testutil:[2024-01-01T01-01-01,)")
100+
testImplementation("de.gesellix:testutil:[2025-01-01T01-01-01,)")
96101
testImplementation("de.gesellix:docker-registry:2025-10-31T17-45-00")
97102
}
98103

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package de.gesellix.docker.authentication;
2+
3+
import java.util.Objects;
4+
5+
public class AuthConfig {
6+
7+
public static final AuthConfig EMPTY_AUTH_CONFIG = new AuthConfig();
8+
9+
private String username;
10+
private String password;
11+
private String auth;
12+
/**
13+
* Email is an optional value associated with the username.
14+
*
15+
* @deprecated This field is deprecated and will be removed in a later version of docker.
16+
*/
17+
@Deprecated
18+
private String email;
19+
private String serveraddress;
20+
private String identitytoken;
21+
private String registrytoken;
22+
23+
public String getUsername() {
24+
return username;
25+
}
26+
27+
public void setUsername(String username) {
28+
this.username = username;
29+
}
30+
31+
public String getPassword() {
32+
return password;
33+
}
34+
35+
public void setPassword(String password) {
36+
this.password = password;
37+
}
38+
39+
public String getAuth() {
40+
return auth;
41+
}
42+
43+
public void setAuth(String auth) {
44+
this.auth = auth;
45+
}
46+
47+
public String getEmail() {
48+
return email;
49+
}
50+
51+
public void setEmail(String email) {
52+
this.email = email;
53+
}
54+
55+
public String getServeraddress() {
56+
return serveraddress;
57+
}
58+
59+
public void setServeraddress(String serveraddress) {
60+
this.serveraddress = serveraddress;
61+
}
62+
63+
public String getIdentitytoken() {
64+
return identitytoken;
65+
}
66+
67+
public void setIdentitytoken(String identitytoken) {
68+
this.identitytoken = identitytoken;
69+
}
70+
71+
public String getRegistrytoken() {
72+
return registrytoken;
73+
}
74+
75+
public void setRegistrytoken(String registrytoken) {
76+
this.registrytoken = registrytoken;
77+
}
78+
79+
@Override
80+
public boolean equals(Object o) {
81+
if (this == o) {return true;}
82+
if (o == null || getClass() != o.getClass()) {return false;}
83+
AuthConfig that = (AuthConfig) o;
84+
return Objects.equals(username, that.username) && Objects.equals(password, that.password) && Objects.equals(auth, that.auth) &&
85+
Objects.equals(email, that.email) && Objects.equals(serveraddress, that.serveraddress) && Objects.equals(identitytoken, that.identitytoken) &&
86+
Objects.equals(registrytoken, that.registrytoken);
87+
}
88+
89+
@Override
90+
public int hashCode() {
91+
return Objects.hash(username, password, auth, email, serveraddress, identitytoken, registrytoken);
92+
}
93+
94+
@Override
95+
public String toString() {
96+
return "AuthConfig{" +
97+
"username='" + username + '\'' +
98+
", password=_redacted_'" + '\'' +
99+
", auth=_redacted_'" + '\'' +
100+
", email='" + email + '\'' +
101+
", serveraddress='" + serveraddress + '\'' +
102+
", identitytoken=_redacted_'" + '\'' +
103+
", registrytoken=_redacted_'" + '\'' +
104+
'}';
105+
}
106+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package de.gesellix.docker.authentication;
2+
3+
import de.gesellix.docker.engine.DockerConfigReader;
4+
import de.gesellix.docker.engine.DockerEnv;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
8+
import java.io.File;
9+
import java.util.Map;
10+
11+
import static de.gesellix.docker.authentication.AuthConfig.EMPTY_AUTH_CONFIG;
12+
13+
public class AuthConfigReader {
14+
15+
private final static Logger log = LoggerFactory.getLogger(AuthConfigReader.class);
16+
17+
private final DockerEnv env;
18+
private final DockerConfigReader dockerConfigReader;
19+
20+
public AuthConfigReader() {
21+
this(new DockerEnv());
22+
}
23+
24+
public AuthConfigReader(DockerEnv env) {
25+
this.env = env;
26+
this.dockerConfigReader = env.getDockerConfigReader();
27+
}
28+
29+
// @Override
30+
public AuthConfig readDefaultAuthConfig() {
31+
return readAuthConfig(null, dockerConfigReader.getDockerConfigFile());
32+
}
33+
34+
// @Override
35+
public AuthConfig readAuthConfig(String hostname, File dockerCfg) {
36+
log.debug("read authConfig");
37+
38+
if (hostname == null || hostname.trim().isEmpty()) {
39+
hostname = env.getIndexUrl_v1();
40+
}
41+
42+
Map parsedDockerCfg = dockerConfigReader.readDockerConfigFile(dockerCfg);
43+
if (parsedDockerCfg == null || parsedDockerCfg.isEmpty()) {
44+
return EMPTY_AUTH_CONFIG;
45+
}
46+
47+
CredsStore credsStore = getCredentialsStore(parsedDockerCfg, hostname);
48+
return credsStore.getAuthConfig(hostname);
49+
}
50+
51+
public CredsStore getCredentialsStore(Map parsedDockerCfg) {
52+
return getCredentialsStore(parsedDockerCfg, "");
53+
}
54+
55+
public CredsStore getCredentialsStore(Map parsedDockerCfg, String hostname) {
56+
if (parsedDockerCfg.containsKey("credHelpers") && hostname != null && !hostname.trim().isEmpty()) {
57+
return new NativeStore((String) ((Map) parsedDockerCfg.get("credHelpers")).get(hostname));
58+
}
59+
if (parsedDockerCfg.containsKey("credsStore")) {
60+
return new NativeStore((String) parsedDockerCfg.get("credsStore"));
61+
}
62+
return new FileStore(parsedDockerCfg);
63+
}
64+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package de.gesellix.docker.authentication;
2+
3+
import java.util.Map;
4+
5+
public interface CredsStore {
6+
7+
String TOKEN_USERNAME = "<token>";
8+
9+
AuthConfig getAuthConfig(String registry);
10+
11+
Map<String, AuthConfig> getAuthConfigs();
12+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package de.gesellix.docker.authentication;
2+
3+
import com.squareup.moshi.Moshi;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
7+
import java.io.BufferedReader;
8+
import java.io.IOException;
9+
import java.io.InputStreamReader;
10+
import java.text.MessageFormat;
11+
import java.util.Map;
12+
import java.util.concurrent.TimeUnit;
13+
import java.util.stream.Collectors;
14+
15+
public class CredsStoreHelper {
16+
17+
private static final Logger log = LoggerFactory.getLogger(CredsStoreHelper.class);
18+
private final Moshi moshi = new Moshi.Builder().build();
19+
20+
public CredsStoreHelperResult getAuthentication(String credsStore, String hostname) {
21+
Result result = execCredsHelper(credsStore, "get", hostname);
22+
return toCredsStoreHelperResult(result, credsStore);
23+
}
24+
25+
public CredsStoreHelperResult getAuthentication(String credsStore) {
26+
return getAuthentication(credsStore, "https://index.docker.io/v1/");
27+
}
28+
29+
public CredsStoreHelperResult getAllAuthentications(String credsStore) {
30+
Result result = execCredsHelper(credsStore, "list", "unused");
31+
return toCredsStoreHelperResult(result, credsStore);
32+
}
33+
34+
public CredsStoreHelperResult toCredsStoreHelperResult(Result result, String credsStore) {
35+
if (!result.getSuccess()) {
36+
return new CredsStoreHelperResult(result.getMessage());
37+
}
38+
39+
try {
40+
return new CredsStoreHelperResult(moshi.adapter(Map.class).fromJson(result.getMessage()));
41+
}
42+
catch (IOException exc) {
43+
log.error(MessageFormat.format("cannot parse docker-credential-{0} result", credsStore), exc);
44+
return new CredsStoreHelperResult(exc.getMessage());
45+
}
46+
catch (Exception exc) {
47+
log.error(MessageFormat.format("error trying to get credentials from docker-credential-{0}", credsStore), exc);
48+
return new CredsStoreHelperResult(exc.getMessage());
49+
}
50+
}
51+
52+
private Result execCredsHelper(String credsStore, String command, String input) {
53+
Process process;
54+
try {
55+
process = new ProcessBuilder(MessageFormat.format("docker-credential-{0}", credsStore), command).redirectErrorStream(true).redirectOutput(ProcessBuilder.Redirect.PIPE).start();
56+
}
57+
catch (Exception exc) {
58+
log.error(MessageFormat.format("error trying to execute docker-credential-{0} {1}", credsStore, command), exc);
59+
return new Result(false, exc.getMessage());
60+
}
61+
62+
BufferedReader buffer = new BufferedReader(new InputStreamReader(process.getInputStream()));
63+
64+
try {
65+
process.getOutputStream().write((input == null ? "".getBytes() : input.getBytes()));
66+
process.getOutputStream().flush();
67+
process.getOutputStream().close();
68+
69+
process.waitFor(10, TimeUnit.SECONDS);
70+
}
71+
catch (IOException | InterruptedException e) {
72+
e.printStackTrace();
73+
}
74+
75+
if (process.exitValue() != 0) {
76+
log.error(MessageFormat.format("docker-credential-{0} {1} failed", credsStore, command));
77+
}
78+
79+
return new Result(process.exitValue() == 0, buffer.lines().collect(Collectors.joining()));
80+
}
81+
82+
public static class Result {
83+
84+
private final boolean success;
85+
private final String message;
86+
87+
public Result(boolean success, String message) {
88+
this.success = success;
89+
this.message = message;
90+
}
91+
92+
public boolean getSuccess() {
93+
return success;
94+
}
95+
96+
public boolean isSuccess() {
97+
return success;
98+
}
99+
100+
public String getMessage() {
101+
return message;
102+
}
103+
}
104+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package de.gesellix.docker.authentication;
2+
3+
import java.util.Map;
4+
import java.util.Objects;
5+
6+
public class CredsStoreHelperResult {
7+
8+
private String error;
9+
private Map<String, Object> data;
10+
11+
public CredsStoreHelperResult(String error) {
12+
this.error = error;
13+
}
14+
15+
public CredsStoreHelperResult(Map<String, Object> data) {
16+
this.data = data;
17+
}
18+
19+
public String getError() {
20+
return error;
21+
}
22+
23+
public Map<String, Object> getData() {
24+
return data;
25+
}
26+
27+
@Override
28+
public boolean equals(Object o) {
29+
if (this == o) {return true;}
30+
if (o == null || getClass() != o.getClass()) {return false;}
31+
CredsStoreHelperResult that = (CredsStoreHelperResult) o;
32+
return Objects.equals(error, that.error) && Objects.equals(data, that.data);
33+
}
34+
35+
@Override
36+
public int hashCode() {
37+
return Objects.hash(error, data);
38+
}
39+
}

0 commit comments

Comments
 (0)