Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply Maven SettingsDecrypter for encrypted server details #609

Merged
merged 11 commits into from
Jul 15, 2018
Merged

Conversation

briandealwis
Copy link
Member

My assumption here is that a decryption error in MavenSettingsServerCredentials should fail the build rather than either return the still-encrypted password or return null (i.e., no configured credentials).

Unsure about MavenSettingsServerCredentials throwing a MojoExecutionException directly, but it seemed unhelpful to create a new exception class that would be immediately turned into a MojoExecutionException.

[ERROR] Failed to execute goal com.google.cloud.tools:jib-maven-plugin:0.9.7-SNAPSHOT:build (default-deploy) on project first: Unable to decrypt settings for registry.hub.docker.com: [ERROR] Failed to decrypt password for server registry.hub.docker.com: org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException: java.io.FileNotFoundException: /Users/bsd/.m2/settings-security.xml (No such file or directory) @ server: registry.hub.docker.com -> [Help 1]

Fixes #592

if (problem.getSeverity() == SettingsProblem.Severity.ERROR
|| problem.getSeverity() == SettingsProblem.Severity.FATAL) {
throw new MojoExecutionException(
"Unable to decrypt settings for " + registry + ": " + problem);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "... decrypt password for ..." is more informative to actual users and has the potential to make them actions on their own.

@eddiewebb
Copy link

eddiewebb commented Jul 13, 2018

Looks like you missed updating method call in BuildTarMojo to pass decrypter. But fixed that and built locally and confirm it does indeed decrypt and publish 🎉

@coollog coollog added this to the v0.9.7 milestone Jul 13, 2018
Copy link
Contributor

@coollog coollog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Just some small comments.

@@ -44,7 +44,6 @@
name = BuildDockerMojo.GOAL_NAME,
requiresDependencyResolution = ResolutionScope.RUNTIME_PLUS_SYSTEM)
public class BuildDockerMojo extends JibPluginConfiguration {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: a line removed (we're following a convention of empty line after class definition for this codebase)

@@ -164,6 +166,8 @@ void handleDeprecatedParameters(BuildLogger logger) {
@Parameter(defaultValue = "${project.basedir}/src/main/jib", required = true)
private String extraDirectory;

@Nullable @Component protected SettingsDecrypter settingsDecrypter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this ever be null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. nullaway complains without it. I did some searching in the Maven docs but didn't find anything authoritative.

The Github Maven Plugins look up the SettingsDecrypter through the plexus container and guard against a ComponentLookupException.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a native question, is it possible fix encrypted passwords and plain passwords (for different servers) in settings.xml? If that's true, I just want to make sure settingsDecrypter handles plain passwords nicely. (I do believe it will.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should do that as well. The case we should guard against is if the user has an encrypted password and SettingsDecrypter was null, there should be some error rather than trying to use the encrypted password and failing to authenticate (by which the user thinks the password is wrong but that's not the case)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @chanseokoh is asking about ~/.m2/settings.xml having both encrypted and unencrypted passwords. The default SettingsDecryptor passes-through unencrypted passwords.

The SettingsDecrypter could theoretically be replaced. In the worse case, where the SettingsDecrypter is null but we have encrypted passwords, we will attempt to authenticate with the encrypted password bytes. But since it was encrypted we won't have divulged anything in the clear. There's no solid way to identity an encrypted vs unencrypted password though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmhmm, I was mostly trying to get at the user experience side, like:

  1. User sets encrypted password in Maven settings
  2. We try to decrypt, but SettingsDecrypter is null, so the password wasn't decrypted
  3. Users sees 401 Unauthorized and believes their password is wrong

Whereas, I think the better UX would be:

  1. User sets encrypted password in Maven settings
  2. We try to decrypt, but SettingsDecrypter is null, so the password wasn't decrypted, and we give an error
  3. Users sees failed to decrypt password (or similar)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default encryption approach seems to surround the passwords with braces.

We could pass in the mavenBuildLogger here and if settingsDecrypter == null and the password starts and ends with braces then issue a warning.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In MavenSettingsServerCredentials#retrieve right? I might be misunderstanding how SettingsDecrypter works, but is there any harm in giving the warning just if settingsDecrypter == null?

}
if (result.getServer() != null) {
registryServer = result.getServer();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is null, should we error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SettingsDecrypter and SettingsDecryptionResult are under-documented and does not discuss the possible meanings of the return results. SettingsDecryptionResult#getServers() does note that:

    /**
     * Gets the decrypted servers.
     *
     * @return The decrypted server, can be empty but never {@code null}.
     */
    List<Server> getServers();

and the implementation of getServer() returns the first element from getServers() and null if there are no servers.

By this point, we have no errors reported from the decryption request, but we have no servers. So one interpretation is: no decryption was required, so use the original server.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense! Let's maybe add a comment about the null case meaning no decryption was required.

@eddiewebb
Copy link

Just a note @briandealwis, according to Maven docs it is valid to put notes inside the password element, but outside the curly braces. So it is not a safe assumption that encrypted values will start with {

<password>Eddie reset this on 2018-07-13 {hsg36sheyeue6duduesy}</password>.

So you'd have to anticipate that in any 'is it encrypted' logic

Copy link
Contributor

@coollog coollog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Just a style comment.


// pattern cribbed directly from
// https://github.com/sonatype/plexus-cipher/blob/master/src/main/java/org/sonatype/plexus/components/cipher/DefaultPlexusCipher.java
private static final Pattern ENCRYPTED_STRING_PATTERN =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this codebase, we're following a convention of organizing classes in the order:

  1. static->non-static
  2. members->inner class->constructor->methods
  3. public->private
  4. final->nonfinal

So a ENCRYPTED_STRING_PATTERN would be under CREDENTIAL_SOURCE, isEncrypted would be under ENCRYPTED_STRING_PATTERN.

@briandealwis briandealwis merged commit f065c30 into master Jul 15, 2018
@briandealwis briandealwis deleted the i592 branch July 15, 2018 02:43
@coollog
Copy link
Contributor

coollog commented Jul 15, 2018

Oh I forgot to mention to include the CHANGELOG entry too.

@chanseokoh chanseokoh mentioned this pull request Jul 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants