Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*-
* -\-\-
* docker-client
* --
* Copyright (C) 2016 Spotify AB
* Copyright (C) 9/2019 - 2020 Dimitris Mandalidis
* --
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* -/-/-
*/
package org.mandas.docker.client;
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.mandas.docker.client.messages.DockerCredentialHelperAuth;
import org.mandas.docker.client.messages.RegistryAuth;
import org.mandas.docker.client.messages.RegistryConfigs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DockerConfigReader {
private static final Logger LOG = LoggerFactory.getLogger(DockerConfigReader.class);
private static final ObjectMapper MAPPER = ObjectMapperProvider.objectMapper();
/**
* Return a single RegistryAuth from the default config file.
* If there is only one, it'll be that one.
*
* @return Some registry auth value.
* @throws IOException when an error occured during reading for docker configuration
*/
public RegistryAuth anyRegistryAuth() throws IOException {
return anyRegistryAuth(defaultConfigPath());
}
/**
* Return a single RegistryAuth from the config file.
* If there are multiple RegistryAuth entries, which entry is returned from this method
* depends on hashing and should not be considered reliable.
* If there is only one entry, however, that will be the one returned. This is the
* primary use of this method, as a useful way to extract a RegistryAuth during testing.
* In that environment, the contents of the config file are known and controlled. In a
* production environment, the contents of the config file are less predictable.
*
* @param configPath Path to the docker config file.
* @return Some registry auth value.
*/
RegistryAuth anyRegistryAuth(final Path configPath) throws IOException {
final Collection registryAuths =
authForAllRegistries(configPath).configs().values();
return registryAuths.isEmpty()
? RegistryAuth.builder().build()
: registryAuths.iterator().next();
}
/**
* Parse the contents of the config file and generate all possible
* {@link RegistryAuth}s, which are bundled into a {@link RegistryConfigs} instance.
* @param configPath Path to config file.
* @return All registry auths that can be generated from the config file
* @throws IOException If the file cannot be read, or its JSON cannot be parsed
*/
public RegistryConfigs authForAllRegistries(final Path configPath) throws IOException {
requireNonNull(configPath);
final DockerConfig config = MAPPER.readValue(configPath.toFile(), DockerConfig.class);
if (config == null) {
return RegistryConfigs.empty();
}
final RegistryConfigs.Builder registryConfigsBuilder = RegistryConfigs.builder();
final Map credHelpers = config.credHelpers();
final boolean hasCredHelpers = credHelpers != null && !credHelpers.isEmpty();
final Map auths = config.auths();
final boolean hasAuths = auths != null && !auths.isEmpty();
final String credsStore = config.credsStore();
final boolean hasCredsStore = credsStore != null;
final Set addedRegistries = new HashSet<>();
// First use the credHelpers, if there are any
if (hasCredHelpers) {
for (final Map.Entry credHelpersEntry : credHelpers.entrySet()) {
final String registry = credHelpersEntry.getKey();
final String aCredsStore = credHelpersEntry.getValue();
if (!addedRegistries.contains(registry)) {
addedRegistries.add(registry);
RegistryAuth authWithCredentialHelper = authWithCredentialHelper(aCredsStore, registry);
if (authWithCredentialHelper != null) {
registryConfigsBuilder.addConfig(registry, authWithCredentialHelper);
}
}
}
}
// If there are any objects in "auths", they could take two forms.
// Older auths will map registry keys to objects with "auth" values, sometimes emails.
// Newer auths will map registry keys to empty objects. They expect you
// to use the credsStore to authenticate.
if (hasAuths) {
// We will use this empty RegistryAuth to check for empty auth values
final RegistryAuth empty = RegistryAuth.builder().build();
for (final Map.Entry authEntry : auths.entrySet()) {
final String registry = authEntry.getKey();
if (addedRegistries.contains(registry)) {
continue;
}
addedRegistries.add(registry);
final RegistryAuth registryAuth = authEntry.getValue();
if (registryAuth == null || registryAuth.equals(empty)) {
// We have an empty object. Can we use credsStore?
if (hasCredsStore) {
registryConfigsBuilder.addConfig(registry,
authWithCredentialHelper(credsStore, registry));
} // no else clause. If we can't fall back to credsStore, we can't auth.
} else {
// The auth object isn't empty.
// We need to add the registry to its properties, then
// add it to the RegistryConfigs
registryConfigsBuilder.addConfig(registry,
registryAuth.toBuilder().serverAddress(registry).build());
}
}
}
// If there are no credHelpers or auths or credsStore, then the
// config may be in a very old format. There aren't any keys for different
// sections. The file is just a map of registries to auths.
// In other words, it looks like a RegistryConfigs.
// If we can map it to one, we'll return it.
if (!(hasAuths || hasCredHelpers || hasCredsStore)) {
try {
return MAPPER.readValue(configPath.toFile(), RegistryConfigs.class);
} catch (IOException ignored) {
// Looks like that failed to parse.
// Eat the exception, fall through, and return empty object.
}
}
return registryConfigsBuilder.build();
}
/**
* Generate {@link RegistryAuth} for the registry.
*
* @param configPath Path to the docker config file
* @param registry Docker registry for which to generate auth
* @return The generated authentication object
* @throws IOException when an error occured while reading the docker configuration
*/
public RegistryAuth authForRegistry(final Path configPath, final String registry)
throws IOException {
requireNonNull(configPath);
requireNonNull(registry);
final DockerConfig config = MAPPER.readValue(configPath.toFile(), DockerConfig.class);
if (config == null) {
return RegistryAuth.builder().build();
}
final RegistryAuth registryAuth = authForRegistry(config, registry);
if (registryAuth != null) {
return registryAuth;
}
// If the given server address didn't have a protocol try adding a protocol to the address.
// This handles cases where older versions of Docker included the protocol when writing
// auth tokens to config.json.
try {
final URI serverAddressUri = new URI(registry);
if (serverAddressUri.getScheme() == null) {
for (String proto : Arrays.asList("https://", "http://")) {
final RegistryAuth protoRegistryAuth = authForRegistry(config, proto + registry);
if (protoRegistryAuth != null) {
return protoRegistryAuth;
}
}
}
} catch (URISyntaxException e) {
LOG.error("Invalid URI", e);
}
throw new IllegalArgumentException(
"registry \"" + registry + "\" does not appear in config file at " + configPath);
}
private RegistryAuth authForRegistry(final DockerConfig config, final String registry)
throws IOException {
// If the registry shows up in "auths", return it
final Map auths = config.auths();
if (auths != null && auths.get(registry) != null) {
return auths.get(registry).toBuilder().serverAddress(registry).build();
}
// Else, we use a credential helper.
final String credsStore = getCredentialStore(config, registry);
if (credsStore != null) {
return authWithCredentialHelper(credsStore, registry);
}
return null;
}
public Path defaultConfigPath() {
if (DockerHost.configPathFromEnv() != null) {
final Path dockerConfig = Paths.get(DockerHost.configPathFromEnv(), "config.json");
LOG.debug("Using config path from DOCKER_CONFIG: {}", dockerConfig);
return dockerConfig;
}
final String home = System.getProperty("user.home");
final Path dockerConfig = Paths.get(home, ".docker", "config.json");
final Path dockerCfg = Paths.get(home, ".dockercfg");
if (Files.exists(dockerConfig)) {
LOG.debug("Using configfile: {}", dockerConfig);
return dockerConfig;
}
LOG.debug("Using configfile: {} ", dockerCfg);
return dockerCfg;
}
/**
* Obtain auth using a credential helper.
* @param credsStore The name of the credential helper
* @param registry The registry for which we need to obtain auth
* @return A RegistryAuth object with a username, password, and server.
* @throws IOException This method attempts to execute
* "docker-credential-" + credsStore + " get". If you don't have the
* proper credential helper installed and on your path, this
* will fail.
*/
private RegistryAuth authWithCredentialHelper(final String credsStore,
final String registry) throws IOException {
final DockerCredentialHelperAuth dockerCredentialHelperAuth =
DockerCredentialHelper.get(credsStore, registry);
return dockerCredentialHelperAuth == null ? null : dockerCredentialHelperAuth.toRegistryAuth();
}
private String getCredentialStore(final DockerConfig config, final String registry) {
requireNonNull(config, "Docker config cannot be null");
requireNonNull(registry, "registry cannot be null");
// Check for the registry in the credHelpers map first.
// If it isn't there, default to credsStore.
final Map credHelpers = config.credHelpers();
return (credHelpers != null && credHelpers.containsKey(registry))
? credHelpers.get(registry)
: config.credsStore();
}
}