You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2013/10/19 14:46:22 UTC
svn commit: r1533747 - in /maven/release/trunk/maven-release-manager/src:
main/java/org/apache/maven/shared/release/exec/
test/java/org/apache/maven/shared/release/exec/
Author: rfscholte
Date: Sat Oct 19 12:46:22 2013
New Revision: 1533747
URL: http://svn.apache.org/r1533747
Log:
[MRELEASE-766] release:prepare stores settings.xml in a public directory
encrypt all passwords and passphrases of the settings.xml
Modified:
maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/AbstractMavenExecutor.java
maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/ForkedMavenExecutor.java
maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/InvokerMavenExecutor.java
maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/ForkedMavenExecutorTest.java
maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/InvokerMavenExecutorTest.java
Modified: maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/AbstractMavenExecutor.java
URL: http://svn.apache.org/viewvc/maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/AbstractMavenExecutor.java?rev=1533747&r1=1533746&r2=1533747&view=diff
==============================================================================
--- maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/AbstractMavenExecutor.java (original)
+++ maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/AbstractMavenExecutor.java Sat Oct 19 12:46:22 2013
@@ -19,16 +19,28 @@ package org.apache.maven.shared.release.
* under the License.
*/
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.SettingsUtils;
+import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
import org.apache.maven.shared.release.ReleaseResult;
import org.apache.maven.shared.release.env.DefaultReleaseEnvironment;
import org.apache.maven.shared.release.env.ReleaseEnvironment;
import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.StringUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
+import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
+import org.sonatype.plexus.components.cipher.PlexusCipher;
+import org.sonatype.plexus.components.cipher.PlexusCipherException;
+import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
+import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
+import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
+import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
public abstract class AbstractMavenExecutor
implements MavenExecutor, LogEnabled
@@ -36,6 +48,19 @@ public abstract class AbstractMavenExecu
private Logger logger;
+ /**
+ * When this plugin requires Maven 3.0 as minimum, this component can be removed and o.a.m.s.c.SettingsDecrypter be
+ * used instead.
+ *
+ * @plexus.requirement role="org.sonatype.plexus.components.sec.dispatcher.SecDispatcher" role-hint="mng-4384"
+ */
+ private DefaultSecDispatcher secDispatcher;
+
+ /**
+ * @plexus.requirement
+ */
+ private PlexusCipher cipher;
+
protected AbstractMavenExecutor()
{
}
@@ -100,4 +125,121 @@ public abstract class AbstractMavenExecu
{
this.logger = logger;
}
+
+
+ protected Settings encryptSettings( Settings settings )
+ {
+ Settings encryptedSettings = SettingsUtils.copySettings( settings );
+
+ for ( Server server : encryptedSettings.getServers() )
+ {
+ String password = server.getPassword();
+ if( password != null && !isEncryptedString( password ) )
+ {
+ try
+ {
+ server.setPassword( encryptAndDecorate( password ) );
+ }
+ catch ( IllegalStateException e )
+ {
+ // ignore
+ }
+ catch ( SecDispatcherException e )
+ {
+ // ignore
+ }
+ catch ( PlexusCipherException e )
+ {
+ // ignore
+ }
+ }
+
+ String passphrase = server.getPassphrase();
+ if( passphrase != null && !isEncryptedString( passphrase ) )
+ {
+ try
+ {
+ server.setPassphrase( encryptAndDecorate( passphrase ) );
+ }
+ catch ( IllegalStateException e )
+ {
+ // ignore
+ }
+ catch ( SecDispatcherException e )
+ {
+ // ignore
+ }
+ catch ( PlexusCipherException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ for ( Proxy proxy : encryptedSettings.getProxies() )
+ {
+ String password = proxy.getPassword();
+ if( password != null && !isEncryptedString( password ) )
+ {
+ try
+ {
+ proxy.setPassword( encryptAndDecorate( password ) );
+ }
+ catch ( IllegalStateException e )
+ {
+ // ignore
+ }
+ catch ( SecDispatcherException e )
+ {
+ // ignore
+ }
+ catch ( PlexusCipherException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ return encryptedSettings;
+ }
+
+ // From org.apache.maven.cli.MavenCli.encryption(CliRequest)
+ private final String encryptAndDecorate( String passwd ) throws IllegalStateException, SecDispatcherException, PlexusCipherException
+ {
+ String configurationFile = secDispatcher.getConfigurationFile();
+
+ if ( configurationFile.startsWith( "~" ) )
+ {
+ configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
+ }
+
+ String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
+
+ String master = null;
+
+ SettingsSecurity sec = SecUtil.read( file, true );
+ if ( sec != null )
+ {
+ master = sec.getMaster();
+ }
+
+ if ( master == null )
+ {
+ throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
+ }
+
+ DefaultPlexusCipher cipher = new DefaultPlexusCipher();
+ String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
+ return cipher.encryptAndDecorate( passwd, masterPasswd );
+ }
+
+ private boolean isEncryptedString( String str )
+ {
+ return cipher.isEncryptedString( str );
+ }
+
+ protected SettingsXpp3Writer getSettingsWriter()
+ {
+ return new SettingsXpp3Writer();
+ }
}
Modified: maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/ForkedMavenExecutor.java
URL: http://svn.apache.org/viewvc/maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/ForkedMavenExecutor.java?rev=1533747&r1=1533746&r2=1533747&view=diff
==============================================================================
--- maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/ForkedMavenExecutor.java (original)
+++ maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/ForkedMavenExecutor.java Sat Oct 19 12:46:22 2013
@@ -77,12 +77,12 @@ public class ForkedMavenExecutor
try
{
settingsFile = File.createTempFile( "release-settings", ".xml" );
- SettingsXpp3Writer writer = new SettingsXpp3Writer();
+ SettingsXpp3Writer writer = getSettingsWriter();
FileWriter fileWriter = null;
try
{
fileWriter = new FileWriter( settingsFile );
- writer.write( fileWriter, releaseEnvironment.getSettings() );
+ writer.write( fileWriter, encryptSettings( releaseEnvironment.getSettings() ) );
}
finally
{
Modified: maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/InvokerMavenExecutor.java
URL: http://svn.apache.org/viewvc/maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/InvokerMavenExecutor.java?rev=1533747&r1=1533746&r2=1533747&view=diff
==============================================================================
--- maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/InvokerMavenExecutor.java (original)
+++ maven/release/trunk/maven-release-manager/src/main/java/org/apache/maven/shared/release/exec/InvokerMavenExecutor.java Sat Oct 19 12:46:22 2013
@@ -176,7 +176,7 @@ public class InvokerMavenExecutor
// TODO: Configuring an invocation request from a command line could as well be part of the Invoker API
protected void setupRequest( InvocationRequest req,
- LoggerBridge bridge,
+ InvokerLogger bridge,
String additionalArguments )
throws MavenExecutorException
{
@@ -327,8 +327,8 @@ public class InvokerMavenExecutor
ReleaseResult result )
throws MavenExecutorException
{
- Handler handler = new Handler( getLogger() );
- LoggerBridge bridge = new LoggerBridge( getLogger() );
+ InvocationOutputHandler handler = getOutputHandler();
+ InvokerLogger bridge = getInvokerLogger();
Invoker invoker =
new DefaultInvoker().setMavenHome( releaseEnvironment.getMavenHome() ).setLogger( bridge ).setOutputHandler(
@@ -350,12 +350,12 @@ public class InvokerMavenExecutor
try
{
settingsFile = File.createTempFile( "release-settings", ".xml" );
- SettingsXpp3Writer writer = new SettingsXpp3Writer();
+ SettingsXpp3Writer writer = getSettingsWriter();
FileWriter fileWriter = null;
try
{
fileWriter = new FileWriter( settingsFile );
- writer.write( fileWriter, releaseEnvironment.getSettings() );
+ writer.write( fileWriter, encryptSettings( releaseEnvironment.getSettings() ) );
}
finally
{
@@ -410,6 +410,16 @@ public class InvokerMavenExecutor
}
}
+ protected InvokerLogger getInvokerLogger()
+ {
+ return new LoggerBridge( getLogger() );
+ }
+
+ protected InvocationOutputHandler getOutputHandler()
+ {
+ return new Handler( getLogger() );
+ }
+
private static final class Handler
implements InvocationOutputHandler
{
Modified: maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/ForkedMavenExecutorTest.java
URL: http://svn.apache.org/viewvc/maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/ForkedMavenExecutorTest.java?rev=1533747&r1=1533746&r2=1533747&view=diff
==============================================================================
--- maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/ForkedMavenExecutorTest.java (original)
+++ maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/ForkedMavenExecutorTest.java Sat Oct 19 12:46:22 2013
@@ -24,6 +24,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -32,12 +33,21 @@ import static org.mockito.Mockito.when;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Writer;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
import org.apache.maven.shared.release.ReleaseResult;
+import org.apache.maven.shared.release.env.DefaultReleaseEnvironment;
+import org.apache.maven.shared.release.env.ReleaseEnvironment;
import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.util.cli.Arg;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.Commandline;
+import org.mockito.ArgumentCaptor;
+import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
/**
* Test the forked Maven executor.
@@ -48,6 +58,8 @@ public class ForkedMavenExecutorTest
extends PlexusTestCase
{
private ForkedMavenExecutor executor;
+
+ private SecDispatcher secDispatcher;
protected void setUp()
throws Exception
@@ -55,6 +67,8 @@ public class ForkedMavenExecutorTest
super.setUp();
executor = (ForkedMavenExecutor) lookup( MavenExecutor.ROLE, "forked-path" );
+
+ secDispatcher = (SecDispatcher) lookup( SecDispatcher.ROLE, "mng-4384" );
}
public void testExecution()
@@ -289,4 +303,67 @@ public class ForkedMavenExecutorTest
verifyNoMoreInteractions( commandLineMock, argMock, commandLineFactoryMock );
}
+
+ public void testEncryptSettings()
+ throws Exception
+ {
+ // prepare
+ File workingDirectory = getTestFile( "target/working-directory" );
+ Process mockProcess = mock( Process.class );
+ when( mockProcess.getInputStream() ).thenReturn( mock( InputStream.class ) );
+ when( mockProcess.getErrorStream() ).thenReturn( mock( InputStream.class ) );
+ when( mockProcess.getOutputStream() ).thenReturn( mock( OutputStream.class ) );
+ when( mockProcess.waitFor() ).thenReturn( 0 );
+
+ Commandline commandLineMock = mock( Commandline.class );
+ when( commandLineMock.execute() ).thenReturn( mockProcess );
+
+ Arg valueArgument = mock( Arg.class );
+ when( commandLineMock.createArg() ).thenReturn( valueArgument );
+
+ CommandLineFactory commandLineFactoryMock = mock( CommandLineFactory.class );
+ when( commandLineFactoryMock.createCommandLine( isA( String.class ) /* "mvn" */) ).thenReturn( commandLineMock );
+
+ executor.setCommandLineFactory( commandLineFactoryMock );
+
+ Settings settings = new Settings();
+ Server server = new Server();
+ server.setPassphrase( "server_passphrase" );
+ server.setPassword( "server_password" );
+ settings.addServer( server );
+ Proxy proxy = new Proxy();
+ proxy.setPassword( "proxy_password" );
+ settings.addProxy( proxy );
+
+ ReleaseEnvironment releaseEnvironment = new DefaultReleaseEnvironment();
+ releaseEnvironment.setSettings( settings );
+
+ AbstractMavenExecutor executorSpy = spy( executor );
+ SettingsXpp3Writer settingsWriter = mock( SettingsXpp3Writer.class );
+
+ ArgumentCaptor<Settings> encryptedSettings = ArgumentCaptor.forClass( Settings.class );
+
+ when( executorSpy.getSettingsWriter() ).thenReturn( settingsWriter );
+
+ executorSpy.executeGoals( workingDirectory, "validate", releaseEnvironment, false, null, new ReleaseResult() );
+
+ verify( settingsWriter ).write( isA( Writer.class ), encryptedSettings.capture() );
+
+ assertNotSame( settings, encryptedSettings.getValue() );
+
+ Server encryptedServer = encryptedSettings.getValue().getServers().get( 0 );
+ assertEquals( "server_passphrase", secDispatcher.decrypt( encryptedServer.getPassphrase() ) );
+ assertEquals( "server_password", secDispatcher.decrypt( encryptedServer.getPassword() ) );
+
+ Proxy encryptedProxy = encryptedSettings.getValue().getProxies().get( 0 );
+ assertEquals( "proxy_password", secDispatcher.decrypt( encryptedProxy.getPassword() ) );
+
+ File settingsSecurity = new File( System.getProperty( "user.home" ), ".m2/settings-security.xml" );
+ if ( settingsSecurity.exists() )
+ {
+ assertFalse( "server_passphrase".equals( encryptedServer.getPassphrase() ) );
+ assertFalse( "server_password".equals( encryptedServer.getPassword() ) );
+ assertFalse( "proxy_password".equals( encryptedProxy.getPassword() ) );
+ }
+ }
}
\ No newline at end of file
Modified: maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/InvokerMavenExecutorTest.java
URL: http://svn.apache.org/viewvc/maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/InvokerMavenExecutorTest.java?rev=1533747&r1=1533746&r2=1533747&view=diff
==============================================================================
--- maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/InvokerMavenExecutorTest.java (original)
+++ maven/release/trunk/maven-release-manager/src/test/java/org/apache/maven/shared/release/exec/InvokerMavenExecutorTest.java Sat Oct 19 12:46:22 2013
@@ -19,46 +19,76 @@ package org.apache.maven.shared.release.
* under the License.
*/
-import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
-
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.Writer;
+
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
+import org.apache.maven.shared.invoker.InvocationOutputHandler;
import org.apache.maven.shared.invoker.InvocationRequest;
+import org.apache.maven.shared.release.ReleaseResult;
+import org.apache.maven.shared.release.env.DefaultReleaseEnvironment;
+import org.apache.maven.shared.release.env.ReleaseEnvironment;
+import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.logging.Logger;
import org.junit.Test;
-
+import org.mockito.ArgumentCaptor;
+import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
public class InvokerMavenExecutorTest
+ extends PlexusTestCase
{
+ private InvokerMavenExecutor executor;
+
+ private SecDispatcher secDispatcher;
+
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+
+ executor = (InvokerMavenExecutor) lookup( MavenExecutor.ROLE, "invoker" );
+
+ secDispatcher = (SecDispatcher) lookup( SecDispatcher.ROLE, "mng-4384" );
+ }
+
@Test
- public void testThreads() throws Exception
+ public void testThreads()
+ throws Exception
{
- InvokerMavenExecutor executor = new InvokerMavenExecutor();
Logger logger = mock( Logger.class );
executor.enableLogging( logger );
-
+
InvocationRequest req = new DefaultInvocationRequest();
executor.setupRequest( req, null, "-T 3" );
assertEquals( "3", req.getThreads() );
-
+
req = new DefaultInvocationRequest();
executor.setupRequest( req, null, "-T4" );
assertEquals( "4", req.getThreads() );
-
+
req = new DefaultInvocationRequest();
executor.setupRequest( req, null, "\"-T5\"" );
assertEquals( "5", req.getThreads() );
-
}
@Test
- public void testGlobalSettings() throws Exception
+ public void testGlobalSettings()
+ throws Exception
{
- InvokerMavenExecutor executor = new InvokerMavenExecutor();
Logger logger = mock( Logger.class );
executor.enableLogging( logger );
-
+
InvocationRequest req = new DefaultInvocationRequest();
executor.setupRequest( req, null, "-gs custom-settings.xml" );
assertEquals( "custom-settings.xml", req.getGlobalSettingsFile().getPath() );
@@ -67,4 +97,61 @@ public class InvokerMavenExecutorTest
executor.setupRequest( req, null, "--global-settings other-settings.xml" );
assertEquals( "other-settings.xml", req.getGlobalSettingsFile().getPath() );
}
+
+ public void testEncryptSettings()
+ throws Exception
+ {
+ // prepare
+ File workingDirectory = getTestFile( "target/working-directory" );
+ workingDirectory.mkdirs();
+
+
+ Settings settings = new Settings();
+ Server server = new Server();
+ server.setPassphrase( "server_passphrase" );
+ server.setPassword( "server_password" );
+ settings.addServer( server );
+ Proxy proxy = new Proxy();
+ proxy.setPassword( "proxy_password" );
+ settings.addProxy( proxy );
+
+ ReleaseEnvironment releaseEnvironment = new DefaultReleaseEnvironment();
+ releaseEnvironment.setSettings( settings );
+
+ InvokerMavenExecutor executorSpy = spy( executor );
+ SettingsXpp3Writer settingsWriter = mock( SettingsXpp3Writer.class );
+
+ ArgumentCaptor<Settings> encryptedSettings = ArgumentCaptor.forClass( Settings.class );
+
+ when( executorSpy.getSettingsWriter() ).thenReturn( settingsWriter );
+ when( executorSpy.getOutputHandler() ).thenReturn( null );
+ when( executorSpy.getInvokerLogger() ).thenReturn( null );
+
+ try
+ {
+ executorSpy.executeGoals( workingDirectory, "validate", releaseEnvironment, false, null, new ReleaseResult() );
+ }
+ catch ( MavenExecutorException e )
+ {
+ }
+
+ verify( settingsWriter ).write( isA( Writer.class ), encryptedSettings.capture() );
+
+ assertNotSame( settings, encryptedSettings.getValue() );
+
+ Server encryptedServer = encryptedSettings.getValue().getServers().get( 0 );
+ assertEquals( "server_passphrase", secDispatcher.decrypt( encryptedServer.getPassphrase() ) );
+ assertEquals( "server_password", secDispatcher.decrypt( encryptedServer.getPassword() ) );
+
+ Proxy encryptedProxy = encryptedSettings.getValue().getProxies().get( 0 );
+ assertEquals( "proxy_password", secDispatcher.decrypt( encryptedProxy.getPassword() ) );
+
+ File settingsSecurity = new File( System.getProperty( "user.home" ), ".m2/settings-security.xml" );
+ if ( settingsSecurity.exists() )
+ {
+ assertFalse( "server_passphrase".equals( encryptedServer.getPassphrase() ) );
+ assertFalse( "server_password".equals( encryptedServer.getPassword() ) );
+ assertFalse( "proxy_password".equals( encryptedProxy.getPassword() ) );
+ }
+ }
}