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.
package io.fabric8.maven.docker.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
import com.google.common.net.UrlEscapers;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.fabric8.maven.docker.access.AuthConfig;
import io.fabric8.maven.docker.access.ecr.EcrExtendedAuth;
/**
* Factory for creating docker specific authentication configuration
*
* @author roland
* @since 29.07.14
*/
public class AuthConfigFactory {
// Properties for specifying username, password (can be encrypted), email and authtoken (not used yet)
// + whether to check for OpenShift authentication
public static final String AUTH_USERNAME = "username";
public static final String AUTH_PASSWORD = "password";
public static final String AUTH_EMAIL = "email";
public static final String AUTH_AUTHTOKEN = "authToken";
private static final String AUTH_USE_OPENSHIFT_AUTH = "useOpenShiftAuth";
static final String DOCKER_LOGIN_DEFAULT_REGISTRY = "https://index.docker.io/v1/";
private final PlexusContainer container;
private Logger log;
private static final String[] DEFAULT_REGISTRIES = new String[]{
"docker.io", "index.docker.io", "registry.hub.docker.com"
};
/**
* Constructor which should be used during startup phase of a plugin
*
* @param container the container used for do decryption of passwords
*/
public AuthConfigFactory(PlexusContainer container) {
this.container = container;
}
public void setLog(Logger log) {
this.log = log;
}
/**
* Create an authentication config object which can be used for communication with a Docker registry
*
* The authentication information is looked up at various places (in this order):
*
*
*
From system properties
*
From the provided map which can contain key-value pairs
*
From the openshift settings in ~/.config/kube
*
From the Maven settings stored typically in ~/.m2/settings.xml
*
From the Docker settings stored in ~/.docker/config.json
*
*
* The following properties (prefix with 'docker.') and config key are evaluated:
*
*
*
username: User to authenticate
*
password: Password to authenticate. Can be encrypted
*
email: Optional EMail address which is send to the registry, too
*
*
* If the repository is in an aws ecr registry and skipExtendedAuth is not true, if found
* credentials are not from docker settings, they will be interpreted as iam credentials
* and exchanged for ecr credentials.
*
* @param isPush if true this AuthConfig is created for a push, if false it's for a pull
* @param skipExtendedAuth if false, do not execute extended authentication methods
* @param authConfig String-String Map holding configuration info from the plugin's configuration. Can be null in
* which case the settings are consulted.
* @param settings the global Maven settings object
* @param user user to check for
* @param registry registry to use, might be null in which case a default registry is checked,
* @return the authentication configuration or null if none could be found
*
* @throws MojoFailureException
*/
public AuthConfig createAuthConfig(boolean isPush, boolean skipExtendedAuth, Map authConfig, Settings settings, String user, String registry)
throws MojoExecutionException {
AuthConfig ret = createStandardAuthConfig(isPush, authConfig, settings, user, registry);
if (ret != null) {
if (registry == null || skipExtendedAuth) {
return ret;
}
try {
return extendedAuthentication(ret, registry);
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
// Finally check ~/.docker/config.json
ret = getAuthConfigFromDockerConfig(registry);
if (ret != null) {
log.debug("AuthConfig: credentials from ~/.docker/config.json");
return ret;
}
log.debug("AuthConfig: no credentials found");
return null;
}
/**
* Try various extended authentication method. Currently only supports amazon ECR
*
* @param standardAuthConfig The locally stored credentials.
* @param registry The registry to authenticated against.
* @return The given credentials, if registry does not need extended authentication;
* else, the credentials after authentication.
* @throws IOException
* @throws MojoExecutionException
*/
private AuthConfig extendedAuthentication(AuthConfig standardAuthConfig, String registry) throws IOException, MojoExecutionException {
EcrExtendedAuth ecr = new EcrExtendedAuth(log, registry);
if (ecr.isAwsRegistry()) {
return ecr.extendedAuth(standardAuthConfig);
}
return standardAuthConfig;
}
/**
* Create an authentication config object which can be used for communication with a Docker registry
*
* The authentication information is looked up at various places (in this order):
*
*
*
From system properties
*
From the provided map which can contain key-value pairs
*
From the openshift settings in ~/.config/kube
*
From the Maven settings stored typically in ~/.m2/settings.xml
*
*
* The following properties (prefix with 'docker.') and config key are evaluated:
*
*
*
username: User to authenticate
*
password: Password to authenticate. Can be encrypted
*
email: Optional EMail address which is send to the registry, too
*
*
*
* @param isPush if true this AuthConfig is created for a push, if false it's for a pull
* @param authConfigMap String-String Map holding configuration info from the plugin's configuration. Can be null in
* which case the settings are consulted.
* @param settings the global Maven settings object
* @param user user to check for
* @param registry registry to use, might be null in which case a default registry is checked,
* @return the authentication configuration or null if none could be found
*
* @throws MojoFailureException
*/
private AuthConfig createStandardAuthConfig(boolean isPush, Map authConfigMap, Settings settings, String user, String registry)
throws MojoExecutionException {
AuthConfig ret;
// Check first for specific configuration based on direction (pull or push), then for a default value
for (LookupMode lookupMode : new LookupMode[] { getLookupMode(isPush), LookupMode.DEFAULT }) {
// System properties docker.username and docker.password always take precedence
ret = getAuthConfigFromSystemProperties(lookupMode);
if (ret != null) {
log.debug("AuthConfig: credentials from system properties");
return ret;
}
// Check for openshift authentication either from the plugin config or from system props
ret = getAuthConfigFromOpenShiftConfig(lookupMode, authConfigMap);
if (ret != null) {
log.debug("AuthConfig: OpenShift credentials");
return ret;
}
// Get configuration from global plugin config
ret = getAuthConfigFromPluginConfiguration(lookupMode, authConfigMap);
if (ret != null) {
log.debug("AuthConfig: credentials from plugin config");
return ret;
}
}
// ===================================================================
// These are lookups based on registry only, so the direction (push or pull) doesn't matter:
// Now lets lookup the registry & user from ~/.m2/setting.xml
ret = getAuthConfigFromSettings(settings, user, registry);
if (ret != null) {
log.debug("AuthConfig: credentials from ~/.m2/setting.xml");
return ret;
}
// check EC2 instance role if registry is ECR
if (EcrExtendedAuth.isAwsRegistry(registry)) {
try {
ret = getAuthConfigFromEC2InstanceRole();
} catch (ConnectTimeoutException ex) {
log.debug("Connection timeout while retrieving instance meta-data, likely not an EC2 instance (%s)",
ex.getMessage());
} catch (IOException ex) {
// don't make that an error since it may fail if not run on an EC2 instance
log.warn("Error while retrieving EC2 instance credentials: %s", ex.getMessage());
}
if (ret != null) {
log.debug("AuthConfig: credentials from EC2 instance role");
return ret;
}
}
// No authentication found
return null;
}
// ===================================================================================================
// if the local credentials don't contain user and password, use EC2 instance
// role credentials
private AuthConfig getAuthConfigFromEC2InstanceRole() throws IOException {
log.debug("No user and password set for ECR, checking EC2 instance role");
try (CloseableHttpClient client = HttpClients.custom().useSystemProperties().build()) {
// we can set very low timeouts because the request returns almost instantly on
// an EC2 instance
// on a non-EC2 instance we can fail early
RequestConfig conf = RequestConfig.custom().setConnectionRequestTimeout(1000).setConnectTimeout(1000)
.setSocketTimeout(1000).build();
// get instance role - if available
HttpGet request = new HttpGet("http://169.254.169.254/latest/meta-data/iam/security-credentials");
request.setConfig(conf);
String instanceRole;
try (CloseableHttpResponse response = client.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
// no instance role found
log.debug("No instance role found, return code was %d", response.getStatusLine().getStatusCode());
return null;
}
// read instance role
try (InputStream is = response.getEntity().getContent()) {
instanceRole = IOUtils.toString(is, StandardCharsets.UTF_8);
}
}
log.debug("Found instance role %s, getting temporary security credentials", instanceRole);
// get temporary credentials
request = new HttpGet("http://169.254.169.254/latest/meta-data/iam/security-credentials/"
+ UrlEscapers.urlPathSegmentEscaper().escape(instanceRole));
request.setConfig(conf);
try (CloseableHttpResponse response = client.execute(request)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
log.debug("No security credential found, return code was %d",
response.getStatusLine().getStatusCode());
// no instance role found
return null;
}
// read instance role
try (Reader r = new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8)) {
JsonObject securityCredentials = new Gson().fromJson(r, JsonObject.class);
String user = securityCredentials.getAsJsonPrimitive("AccessKeyId").getAsString();
String password = securityCredentials.getAsJsonPrimitive("SecretAccessKey").getAsString();
String token = securityCredentials.getAsJsonPrimitive("Token").getAsString();
log.debug("Received temporary access key %s...", user.substring(0, 8));
return new AuthConfig(user, password, "none", token);
}
}
}
}
private AuthConfig getAuthConfigFromSystemProperties(LookupMode lookupMode) throws MojoExecutionException {
Properties props = System.getProperties();
String userKey = lookupMode.asSysProperty(AUTH_USERNAME);
String passwordKey = lookupMode.asSysProperty(AUTH_PASSWORD);
if (props.containsKey(userKey)) {
if (!props.containsKey(passwordKey)) {
throw new MojoExecutionException("No " + passwordKey + " provided for username " + props.getProperty(userKey));
}
return new AuthConfig(props.getProperty(userKey),
decrypt(props.getProperty(passwordKey)),
props.getProperty(lookupMode.asSysProperty(AUTH_EMAIL)),
props.getProperty(lookupMode.asSysProperty(AUTH_AUTHTOKEN)));
} else {
return null;
}
}
private AuthConfig getAuthConfigFromOpenShiftConfig(LookupMode lookupMode, Map authConfigMap) throws MojoExecutionException {
Properties props = System.getProperties();
String useOpenAuthModeProp = lookupMode.asSysProperty(AUTH_USE_OPENSHIFT_AUTH);
// Check for system property
if (props.containsKey(useOpenAuthModeProp)) {
boolean useOpenShift = Boolean.valueOf(props.getProperty(useOpenAuthModeProp));
if (useOpenShift) {
return validateMandatoryOpenShiftLogin(parseOpenShiftConfig(), useOpenAuthModeProp);
} else {
return null;
}
}
// Check plugin config
Map mapToCheck = getAuthConfigMapToCheck(lookupMode,authConfigMap);
if (mapToCheck != null && mapToCheck.containsKey(AUTH_USE_OPENSHIFT_AUTH) &&
Boolean.valueOf((String) mapToCheck.get(AUTH_USE_OPENSHIFT_AUTH))) {
return validateMandatoryOpenShiftLogin(parseOpenShiftConfig(), useOpenAuthModeProp);
} else {
return null;
}
}
private AuthConfig getAuthConfigFromPluginConfiguration(LookupMode lookupMode, Map authConfig) throws MojoExecutionException {
Map mapToCheck = getAuthConfigMapToCheck(lookupMode,authConfig);
if (mapToCheck != null && mapToCheck.containsKey(AUTH_USERNAME)) {
if (!mapToCheck.containsKey(AUTH_PASSWORD)) {
throw new MojoExecutionException("No 'password' given while using in configuration for mode " + lookupMode);
}
Map cloneConfig = new HashMap<>(mapToCheck);
cloneConfig.put(AUTH_PASSWORD, decrypt(cloneConfig.get(AUTH_PASSWORD)));
return new AuthConfig(cloneConfig);
} else {
return null;
}
}
private AuthConfig getAuthConfigFromSettings(Settings settings, String user, String registry) throws MojoExecutionException {
Server defaultServer = null;
Server found;
for (Server server : settings.getServers()) {
String id = server.getId();
// Remember a default server without user as fallback for later
if (defaultServer == null) {
defaultServer = checkForServer(server, id, registry, null);
}
// Check for specific server with user part
found = checkForServer(server, id, registry, user);
if (found != null) {
return createAuthConfigFromServer(found);
}
}
return defaultServer != null ? createAuthConfigFromServer(defaultServer) : null;
}
private AuthConfig getAuthConfigFromDockerConfig(String registry) throws MojoExecutionException {
JsonObject dockerConfig = DockerFileUtil.readDockerConfig();
if (dockerConfig == null) {
return null;
}
String registryToLookup = registry != null ? registry : DOCKER_LOGIN_DEFAULT_REGISTRY;
if (dockerConfig.has("credHelpers") || dockerConfig.has("credsStore")) {
if (dockerConfig.has("credHelpers")) {
final JsonObject credHelpers = dockerConfig.getAsJsonObject("credHelpers");
if (credHelpers.has(registryToLookup)) {
return extractAuthConfigFromCredentialsHelper(registryToLookup, credHelpers.get(registryToLookup).getAsString());
}
}
if (dockerConfig.has("credsStore")) {
return extractAuthConfigFromCredentialsHelper(registryToLookup, dockerConfig.get("credsStore").getAsString());
}
}
if (dockerConfig.has("auths")) {
return extractAuthConfigFromAuths(registryToLookup, dockerConfig.getAsJsonObject("auths"));
}
return null;
}
private AuthConfig extractAuthConfigFromAuths(String registryToLookup, JsonObject auths) {
JsonObject credentials = getCredentialsNode(auths,registryToLookup);
if (credentials == null || !credentials.has("auth")) {
return null;
}
String auth = credentials.get("auth").getAsString();
String email = credentials.has(AUTH_EMAIL) ? credentials.get(AUTH_EMAIL).getAsString() : null;
return new AuthConfig(auth,email);
}
private AuthConfig extractAuthConfigFromCredentialsHelper(String registryToLookup, String credConfig) throws MojoExecutionException {
CredentialHelperClient credentialHelper = new CredentialHelperClient(log, credConfig);
String version = credentialHelper.getVersion();
log.debug("AuthConfig: credentials from credential helper/store %s%s",
credentialHelper.getName(),
version != null ? " version " + version : "");
return credentialHelper.getAuthConfig(registryToLookup);
}
private JsonObject getCredentialsNode(JsonObject auths,String registryToLookup) {
if (auths.has(registryToLookup)) {
return auths.getAsJsonObject(registryToLookup);
}
String registryWithScheme = EnvUtil.ensureRegistryHttpUrl(registryToLookup);
if (auths.has(registryWithScheme)) {
return auths.getAsJsonObject(registryWithScheme);
}
return null;
}
// =======================================================================================================
private Map getAuthConfigMapToCheck(LookupMode lookupMode, Map authConfigMap) {
String configMapKey = lookupMode.getConfigMapKey();
if (configMapKey == null) {
return authConfigMap;
}
if (authConfigMap != null) {
return (Map) authConfigMap.get(configMapKey);
}
return null;
}
// Parse OpenShift config to get credentials, but return null if not found
private AuthConfig parseOpenShiftConfig() {
Map kubeConfig = DockerFileUtil.readKubeConfig();
if (kubeConfig == null) {
return null;
}
String currentContextName = (String) kubeConfig.get("current-context");
if (currentContextName == null) {
return null;
}
for (Map contextMap : (List