Repository: jclouds
Updated Branches:
  refs/heads/master 04c2394a1 -> bde70457d


Properly set the permissions in the ~/.ssh folder

When writing the ~/.ssh/authorized_keys file in a script that is being
run as sudo, the file is created with the root owner, instead of the
user defined by the node credentials. File ownership should be enforced
to make sure the right owner is alwaays set.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/179ed3b2
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/179ed3b2
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/179ed3b2

Branch: refs/heads/master
Commit: 179ed3b2f6688ca51e579ac3451945b2d015b279
Parents: 04c2394
Author: Ignasi Barrera <[email protected]>
Authored: Thu Jun 16 23:32:07 2016 +0200
Committer: Ignasi Barrera <[email protected]>
Committed: Fri Jun 17 22:16:19 2016 +0200

----------------------------------------------------------------------
 .../config/BaseComputeServiceContextModule.java |  3 -
 .../functions/InstallKeysAndRunScript.java      | 59 +++++++++++++++
 .../NodeAndTemplateOptionsToStatement.java      | 40 +++++++++++
 ...plateOptionsToStatementWithoutPublicKey.java | 60 ++++++++++++++++
 .../functions/TemplateOptionsToStatement.java   | 55 --------------
 ...AndAddToGoodMapOrPutExceptionIntoBadMap.java | 14 ++--
 ...eOptionsToStatementWithoutPublicKeyTest.java | 74 +++++++++++++++++++
 ...ddToGoodMapOrPutExceptionIntoBadMapTest.java | 11 +--
 .../src/test/resources/initscript_with_java.sh  |  1 +
 .../src/test/resources/initscript_with_jetty.sh |  1 +
 .../src/test/resources/runscript_adminUpdate.sh |  1 +
 ...igitalOcean2ComputeServiceContextModule.java |  6 +-
 ...plateOptionsToStatementWithoutPublicKey.java | 59 ---------------
 ...eOptionsToStatementWithoutPublicKeyTest.java | 75 --------------------
 .../scriptbuilder/statements/login/UserAdd.java |  2 +-
 .../statements/ssh/AuthorizeRSAPublicKeys.java  | 16 ++++-
 .../statements/login/UserAddTest.java           |  2 +-
 .../ssh/AuthorizeRSAPublicKeyTest.java          | 28 ++++++--
 .../test/resources/test_adminaccess_flipped.sh  |  1 +
 .../test/resources/test_adminaccess_params.sh   |  1 +
 .../test_adminaccess_params_and_fullname.sh     |  1 +
 .../resources/test_adminaccess_plainuser.sh     |  1 +
 .../test/resources/test_adminaccess_standard.sh |  1 +
 23 files changed, 294 insertions(+), 218 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git 
a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
 
b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
index 4acaef9..8d9aa0e 100644
--- 
a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
+++ 
b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
@@ -47,7 +47,6 @@ import org.jclouds.compute.extensions.ImageExtension;
 import org.jclouds.compute.extensions.SecurityGroupExtension;
 import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode;
 import 
org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials;
-import org.jclouds.compute.functions.TemplateOptionsToStatement;
 import org.jclouds.compute.options.RunScriptOptions;
 import org.jclouds.compute.options.TemplateOptions;
 import org.jclouds.compute.reference.ComputeServiceConstants;
@@ -89,8 +88,6 @@ public abstract class BaseComputeServiceContextModule extends 
AbstractModule {
       install(new ComputeServiceTimeoutsModule());
       bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() {
       }).to(CreateSshClientOncePortIsListeningOnNode.class);
-      bind(new TypeLiteral<Function<TemplateOptions, Statement>>() {
-      }).to(TemplateOptionsToStatement.class);
       
bind(LoginCredentials.class).annotatedWith(Names.named("image")).toProvider(
             
GetLoginForProviderFromPropertiesAndStoreCredentialsOrReturnNull.class);
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/main/java/org/jclouds/compute/functions/InstallKeysAndRunScript.java
----------------------------------------------------------------------
diff --git 
a/compute/src/main/java/org/jclouds/compute/functions/InstallKeysAndRunScript.java
 
b/compute/src/main/java/org/jclouds/compute/functions/InstallKeysAndRunScript.java
new file mode 100644
index 0000000..594c424
--- /dev/null
+++ 
b/compute/src/main/java/org/jclouds/compute/functions/InstallKeysAndRunScript.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.compute.functions;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.List;
+
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.scriptbuilder.InitScript;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
+import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
+
+import com.google.common.collect.ImmutableSet;
+
+@Singleton
+public class InstallKeysAndRunScript implements 
NodeAndTemplateOptionsToStatement {
+
+   @Override
+   public Statement apply(NodeMetadata node, TemplateOptions options) {
+      String user = options.getLoginUser();
+      if (user == null && node.getCredentials() != null) {
+         user = node.getCredentials().getUser();
+      }
+      List<Statement> bootstrap = newArrayList();
+      if (options.getPublicKey() != null)
+         bootstrap.add(new 
AuthorizeRSAPublicKeys(ImmutableSet.of(options.getPublicKey()), user));
+      if (options.getRunScript() != null)
+         bootstrap.add(options.getRunScript());
+      if (options.getPrivateKey() != null)
+         bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey()));
+      if (bootstrap.size() >= 1) {
+         if (options.getTaskName() == null && !(options.getRunScript() 
instanceof InitScript))
+            options.nameTask("bootstrap");
+         return bootstrap.size() == 1 ? bootstrap.get(0) : new 
StatementList(bootstrap);
+      }
+      return null;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatement.java
----------------------------------------------------------------------
diff --git 
a/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatement.java
 
b/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatement.java
new file mode 100644
index 0000000..90c74b6
--- /dev/null
+++ 
b/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatement.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.compute.functions;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.scriptbuilder.domain.Statement;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Returns the statement to be executed on the node.
+ */
+@ImplementedBy(InstallKeysAndRunScript.class)
+public interface NodeAndTemplateOptionsToStatement {
+
+   /**
+    * Returns the script that has to be executed in the given node.
+    * 
+    * @return The script to be executed or <code>null</code> if no script needs
+    *         to be run.
+    */
+   @Nullable
+   Statement apply(NodeMetadata node, TemplateOptions options);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKey.java
----------------------------------------------------------------------
diff --git 
a/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKey.java
 
b/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKey.java
new file mode 100644
index 0000000..c4e26dd
--- /dev/null
+++ 
b/compute/src/main/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKey.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.compute.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.scriptbuilder.InitScript;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Convert the node and template options into a statement, but ignoring the
+ * public key.
+ * <p>
+ * Providers that can install the public key using their API should bind this
+ * strategy to avoid an unnecessary SSH connection to manually upload it.
+ */
+@Singleton
+public class NodeAndTemplateOptionsToStatementWithoutPublicKey implements 
NodeAndTemplateOptionsToStatement {
+
+   @Override
+   public Statement apply(NodeMetadata node, TemplateOptions options) {
+      ImmutableList.Builder<Statement> builder = ImmutableList.builder();
+      if (options.getRunScript() != null) {
+         builder.add(options.getRunScript());
+      }
+      if (options.getPrivateKey() != null) {
+         builder.add(new InstallRSAPrivateKey(options.getPrivateKey()));
+      }
+
+      ImmutableList<Statement> bootstrap = builder.build();
+      if (!bootstrap.isEmpty()) {
+         if (options.getTaskName() == null && !(options.getRunScript() 
instanceof InitScript)) {
+            options.nameTask("bootstrap");
+         }
+         return bootstrap.size() == 1 ? bootstrap.get(0) : new 
StatementList(bootstrap);
+      }
+
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java
----------------------------------------------------------------------
diff --git 
a/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java
 
b/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java
deleted file mode 100644
index 87d299d..0000000
--- 
a/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.jclouds.compute.functions;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-import java.util.List;
-
-import javax.inject.Singleton;
-
-import org.jclouds.compute.options.TemplateOptions;
-import org.jclouds.scriptbuilder.InitScript;
-import org.jclouds.scriptbuilder.domain.Statement;
-import org.jclouds.scriptbuilder.domain.StatementList;
-import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
-import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableSet;
-
-@Singleton
-public class TemplateOptionsToStatement implements Function<TemplateOptions, 
Statement> {
-
-   @Override
-   public Statement apply(TemplateOptions options) {
-      List<Statement> bootstrap = newArrayList();
-      if (options.getPublicKey() != null)
-         bootstrap.add(new 
AuthorizeRSAPublicKeys(ImmutableSet.of(options.getPublicKey())));
-      if (options.getRunScript() != null)
-         bootstrap.add(options.getRunScript());
-      if (options.getPrivateKey() != null)
-         bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey()));
-      if (bootstrap.size() >= 1) {
-         if (options.getTaskName() == null && !(options.getRunScript() 
instanceof InitScript))
-            options.nameTask("bootstrap");
-         return bootstrap.size() == 1 ? bootstrap.get(0) : new 
StatementList(bootstrap);
-      }
-      return null;
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java
----------------------------------------------------------------------
diff --git 
a/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java
 
b/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java
index 98419d1..2bb383c 100644
--- 
a/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java
+++ 
b/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java
@@ -34,6 +34,7 @@ import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.config.CustomizationResponse;
 import org.jclouds.compute.domain.ExecResponse;
 import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
 import org.jclouds.compute.options.TemplateOptions;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.compute.util.OpenSocketFinder;
@@ -66,7 +67,7 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
    private final OpenSocketFinder openSocketFinder;
 
    @Nullable
-   private final Statement statement;
+   private final NodeAndTemplateOptionsToStatement 
nodeAndTemplateOptionsToStatement;
    private final TemplateOptions options;
    private AtomicReference<NodeMetadata> node;
    private final Set<NodeMetadata> goodNodes;
@@ -78,13 +79,13 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
    @AssistedInject
    public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
          @Named(TIMEOUT_NODE_RUNNING) Function<AtomicReference<NodeMetadata>, 
AtomicReference<NodeMetadata>> pollNodeRunning,
-         OpenSocketFinder openSocketFinder, Function<TemplateOptions, 
Statement> templateOptionsToStatement,
+         OpenSocketFinder openSocketFinder, NodeAndTemplateOptionsToStatement 
nodeAndTemplateOptionsToStatement,
          InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory, @Assisted TemplateOptions options,
          @Assisted AtomicReference<NodeMetadata> node, @Assisted 
Set<NodeMetadata> goodNodes,
          @Assisted Map<NodeMetadata, Exception> badNodes,
          @Assisted Multimap<NodeMetadata, CustomizationResponse> 
customizationResponses) {
-      this.statement = checkNotNull(templateOptionsToStatement, 
"templateOptionsToStatement").apply(
-            checkNotNull(options, "options"));
+      this.nodeAndTemplateOptionsToStatement = 
checkNotNull(nodeAndTemplateOptionsToStatement,
+            "nodeAndTemplateOptionsToStatement");
       this.pollNodeRunning = checkNotNull(pollNodeRunning, "pollNodeRunning");
       this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, 
"initScriptRunnerFactory");
       this.openSocketFinder = checkNotNull(openSocketFinder, 
"openSocketFinder");
@@ -99,11 +100,11 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
    public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
          @Named(TIMEOUT_NODE_RUNNING) Function<AtomicReference<NodeMetadata>, 
AtomicReference<NodeMetadata>> pollNodeRunning,
          GetNodeMetadataStrategy getNode, OpenSocketFinder openSocketFinder,
-         Function<TemplateOptions, Statement> templateOptionsToStatement,
+         NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement,
          InitializeRunScriptOnNodeOrPlaceInBadMap.Factory 
initScriptRunnerFactory, @Assisted TemplateOptions options,
          @Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, 
Exception> badNodes,
          @Assisted Multimap<NodeMetadata, CustomizationResponse> 
customizationResponses) {
-      this(pollNodeRunning, openSocketFinder, templateOptionsToStatement, 
initScriptRunnerFactory, options,
+      this(pollNodeRunning, openSocketFinder, 
nodeAndTemplateOptionsToStatement, initScriptRunnerFactory, options,
             new AtomicReference<NodeMetadata>(null), goodNodes, badNodes, 
customizationResponses);
    }
 
@@ -115,6 +116,7 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
       try {
          if (options.shouldBlockUntilRunning()) {
             pollNodeRunning.apply(node);
+            Statement statement = 
nodeAndTemplateOptionsToStatement.apply(node.get(), options);
             if (statement != null) {
                RunScriptOnNode runner = 
initScriptRunnerFactory.create(node.get(), statement, options, badNodes).call();
                if (runner != null) {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/test/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKeyTest.java
----------------------------------------------------------------------
diff --git 
a/compute/src/test/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKeyTest.java
 
b/compute/src/test/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKeyTest.java
new file mode 100644
index 0000000..d85dc75
--- /dev/null
+++ 
b/compute/src/test/java/org/jclouds/compute/functions/NodeAndTemplateOptionsToStatementWithoutPublicKeyTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.compute.functions;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.scriptbuilder.domain.OsFamily;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
+import org.jclouds.ssh.SshKeys;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link 
NodeAndTemplateOptionsToStatementWithoutPublicKey} class.
+ */
+@Test(groups = "unit", testName = 
"NodeAndTemplateOptionsToStatementWithoutPublicKeyTest")
+public class NodeAndTemplateOptionsToStatementWithoutPublicKeyTest {
+
+   @Test
+   public void 
testPublicKeyDoesNotGenerateAuthorizePublicKeyStatementIfOnlyPublicKeyOptionsConfigured()
 {
+      Map<String, String> keys = SshKeys.generate();
+      TemplateOptions options = 
TemplateOptions.Builder.authorizePublicKey(keys.get("public"));
+      NodeAndTemplateOptionsToStatementWithoutPublicKey function = new 
NodeAndTemplateOptionsToStatementWithoutPublicKey();
+      assertNull(function.apply(null, options));
+   }
+
+   @Test
+   public void 
testPublicAndRunScriptKeyDoesNotGenerateAuthorizePublicKeyStatementIfRunScriptPresent()
 {
+      Map<String, String> keys = SshKeys.generate();
+      TemplateOptions options = 
TemplateOptions.Builder.authorizePublicKey(keys.get("public")).runScript("uptime");
+
+      NodeAndTemplateOptionsToStatementWithoutPublicKey function = new 
NodeAndTemplateOptionsToStatementWithoutPublicKey();
+      Statement statement = function.apply(null, options);
+
+      assertEquals(statement.render(OsFamily.UNIX), "uptime\n");
+   }
+
+   @Test
+   public void 
testPublicAndPrivateKeyAndRunScriptDoesNotGenerateAuthorizePublicKeyStatementIfOtherOptionsPresent()
 {
+      Map<String, String> keys = SshKeys.generate();
+      TemplateOptions options = 
TemplateOptions.Builder.authorizePublicKey(keys.get("public"))
+            .installPrivateKey(keys.get("private")).runScript("uptime");
+
+      NodeAndTemplateOptionsToStatementWithoutPublicKey function = new 
NodeAndTemplateOptionsToStatementWithoutPublicKey();
+      Statement statement = function.apply(null, options);
+
+      assertTrue(statement instanceof StatementList);
+      StatementList statements = (StatementList) statement;
+
+      assertEquals(statements.size(), 2);
+      assertEquals(statements.get(0).render(OsFamily.UNIX), "uptime\n");
+      assertTrue(statements.get(1) instanceof InstallRSAPrivateKey);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java
----------------------------------------------------------------------
diff --git 
a/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java
 
b/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java
index 822bd84..857c006 100644
--- 
a/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java
+++ 
b/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java
@@ -32,7 +32,8 @@ import org.jclouds.compute.config.CustomizationResponse;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.NodeMetadata.Status;
 import org.jclouds.compute.domain.NodeMetadataBuilder;
-import org.jclouds.compute.functions.TemplateOptionsToStatement;
+import org.jclouds.compute.functions.InstallKeysAndRunScript;
+import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
 import org.jclouds.compute.options.TemplateOptions;
 import org.jclouds.compute.util.OpenSocketFinder;
 import org.jclouds.scriptbuilder.domain.Statement;
@@ -53,7 +54,7 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
    public void testBreakOnIllegalStateExceptionDuringPollNode() {
       InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory 
= createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
       OpenSocketFinder openSocketFinder = createMock(OpenSocketFinder.class);
-      Function<TemplateOptions, Statement> templateOptionsToStatement = new 
TemplateOptionsToStatement();
+      NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement = 
new InstallKeysAndRunScript();
       @SuppressWarnings("unused")
       Statement statement = null;
       TemplateOptions options = new TemplateOptions();
@@ -79,7 +80,7 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
       // run
       AtomicReference<NodeMetadata> atomicNode = 
Atomics.newReference(pendingNode);
       new 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(pollNodeRunning, 
openSocketFinder,
-            templateOptionsToStatement, initScriptRunnerFactory, options, 
atomicNode, goodNodes, badNodes,
+            nodeAndTemplateOptionsToStatement, initScriptRunnerFactory, 
options, atomicNode, goodNodes, badNodes,
             customizationResponses).apply(atomicNode);
 
       assertEquals(goodNodes.size(), 0);
@@ -95,7 +96,7 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
       int portTimeoutSecs = 2;
       InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory 
= createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
       OpenSocketFinder openSocketFinder = createMock(OpenSocketFinder.class);
-      Function<TemplateOptions, Statement> templateOptionsToStatement = new 
TemplateOptionsToStatement();
+      NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement = 
new InstallKeysAndRunScript();
       TemplateOptions options = new TemplateOptions().blockOnPort(22, 
portTimeoutSecs);
       Set<NodeMetadata> goodNodes = Sets.newLinkedHashSet();
       Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
@@ -124,7 +125,7 @@ public class 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
       // run
       AtomicReference<NodeMetadata> atomicNode = 
Atomics.newReference(pendingNode);
       new 
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(pollNodeRunning, 
openSocketFinder,
-            templateOptionsToStatement, initScriptRunnerFactory, options, 
atomicNode, goodNodes, badNodes,
+            nodeAndTemplateOptionsToStatement, initScriptRunnerFactory, 
options, atomicNode, goodNodes, badNodes,
             customizationResponses).apply(atomicNode);
 
       assertEquals(goodNodes.size(), 0);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/test/resources/initscript_with_java.sh
----------------------------------------------------------------------
diff --git a/compute/src/test/resources/initscript_with_java.sh 
b/compute/src/test/resources/initscript_with_java.sh
index 6c2d077..bea054a 100644
--- a/compute/src/test/resources/initscript_with_java.sh
+++ b/compute/src/test/resources/initscript_with_java.sh
@@ -219,6 +219,7 @@ END_OF_JCLOUDS_SCRIPT
                publicKey
        END_OF_JCLOUDS_FILE
        chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
+       chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
        chown -R defaultAdminUsername /home/users/defaultAdminUsername
        exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
        PermitRootLogin no

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/test/resources/initscript_with_jetty.sh
----------------------------------------------------------------------
diff --git a/compute/src/test/resources/initscript_with_jetty.sh 
b/compute/src/test/resources/initscript_with_jetty.sh
index 1e66242..3b399cd 100644
--- a/compute/src/test/resources/initscript_with_jetty.sh
+++ b/compute/src/test/resources/initscript_with_jetty.sh
@@ -219,6 +219,7 @@ END_OF_JCLOUDS_SCRIPT
                publicKey
        END_OF_JCLOUDS_FILE
        chmod 600 /home/users/web/.ssh/authorized_keys
+       chown -R web /home/users/web/.ssh
        chown -R web /home/users/web
        exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
        PermitRootLogin no

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/compute/src/test/resources/runscript_adminUpdate.sh
----------------------------------------------------------------------
diff --git a/compute/src/test/resources/runscript_adminUpdate.sh 
b/compute/src/test/resources/runscript_adminUpdate.sh
index eca129a..9d2ade9 100644
--- a/compute/src/test/resources/runscript_adminUpdate.sh
+++ b/compute/src/test/resources/runscript_adminUpdate.sh
@@ -100,6 +100,7 @@ END_OF_JCLOUDS_SCRIPT
                publicKey
        END_OF_JCLOUDS_FILE
        chmod 600 /over/ridden/foo/.ssh/authorized_keys
+       chown -R foo /over/ridden/foo/.ssh
        chown -R foo /over/ridden/foo
        exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
        PermitRootLogin no

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git 
a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java
 
b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java
index 03caf85..e5b59ba 100644
--- 
a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java
+++ 
b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java
@@ -32,7 +32,8 @@ import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.NodeMetadata.Status;
 import org.jclouds.compute.extensions.ImageExtension;
-import org.jclouds.compute.functions.TemplateOptionsToStatement;
+import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
+import 
org.jclouds.compute.functions.NodeAndTemplateOptionsToStatementWithoutPublicKey;
 import org.jclouds.compute.options.TemplateOptions;
 import org.jclouds.compute.reference.ComputeServiceConstants.PollPeriod;
 import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
@@ -45,7 +46,6 @@ import 
org.jclouds.digitalocean2.compute.functions.DropletToNodeMetadata;
 import org.jclouds.digitalocean2.compute.functions.ImageInRegionToImage;
 import org.jclouds.digitalocean2.compute.functions.RegionToLocation;
 import org.jclouds.digitalocean2.compute.functions.SizeToHardware;
-import 
org.jclouds.digitalocean2.compute.functions.TemplateOptionsToStatementWithoutPublicKey;
 import org.jclouds.digitalocean2.compute.internal.ImageInRegion;
 import org.jclouds.digitalocean2.compute.options.DigitalOcean2TemplateOptions;
 import 
org.jclouds.digitalocean2.compute.strategy.CreateKeyPairsThenCreateNodes;
@@ -91,7 +91,7 @@ public class DigitalOcean2ComputeServiceContextModule extends
 
       
bind(CreateNodesInGroupThenAddToSet.class).to(CreateKeyPairsThenCreateNodes.class);
       bind(TemplateOptions.class).to(DigitalOcean2TemplateOptions.class);
-      
bind(TemplateOptionsToStatement.class).to(TemplateOptionsToStatementWithoutPublicKey.class);
+      
bind(NodeAndTemplateOptionsToStatement.class).to(NodeAndTemplateOptionsToStatementWithoutPublicKey.class);
 
       bind(new TypeLiteral<ImageExtension>() {
       }).to(DigitalOcean2ImageExtension.class);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java
----------------------------------------------------------------------
diff --git 
a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java
 
b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java
deleted file mode 100644
index 52dcb0e..0000000
--- 
a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.jclouds.digitalocean2.compute.functions;
-
-import javax.inject.Singleton;
-
-import org.jclouds.compute.functions.TemplateOptionsToStatement;
-import org.jclouds.compute.options.TemplateOptions;
-import org.jclouds.scriptbuilder.InitScript;
-import org.jclouds.scriptbuilder.domain.Statement;
-import org.jclouds.scriptbuilder.domain.StatementList;
-import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
-import com.google.common.collect.ImmutableList;
-
-/**
- * Convert the template options into a statement, but ignoring the public key.
- * <p>
- * The {@link 
org.jclouds.DigitalOcean2ComputeServiceAdapter.compute.strategy.DigitalOceanComputeServiceAdapter}
 already takes care of
- * installing it using the {@link 
org.jclouds.digitalocean.features.KeyPairApi}.
- */
-@Singleton
-public class TemplateOptionsToStatementWithoutPublicKey extends 
TemplateOptionsToStatement {
-
-   @Override
-   public Statement apply(TemplateOptions options) {
-      ImmutableList.Builder<Statement> builder = ImmutableList.builder();
-      if (options.getRunScript() != null) {
-         builder.add(options.getRunScript());
-      }
-      if (options.getPrivateKey() != null) {
-         builder.add(new InstallRSAPrivateKey(options.getPrivateKey()));
-      }
-
-      ImmutableList<Statement> bootstrap = builder.build();
-      if (!bootstrap.isEmpty()) {
-         if (options.getTaskName() == null && !(options.getRunScript() 
instanceof InitScript)) {
-            options.nameTask("bootstrap");
-         }
-         return bootstrap.size() == 1 ? bootstrap.get(0) : new 
StatementList(bootstrap);
-      }
-
-      return null;
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java
----------------------------------------------------------------------
diff --git 
a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java
 
b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java
deleted file mode 100644
index c3a6cd2..0000000
--- 
a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.jclouds.digitalocean2.compute.functions;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Map;
-
-import org.jclouds.compute.options.TemplateOptions;
-import org.jclouds.scriptbuilder.domain.OsFamily;
-import org.jclouds.scriptbuilder.domain.Statement;
-import org.jclouds.scriptbuilder.domain.StatementList;
-import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
-import org.jclouds.ssh.SshKeys;
-import org.testng.annotations.Test;
-
-/**
- * Unit tests for the {@link TemplateOptionsToStatementWithoutPublicKey} class.
- */
-@Test(groups = "unit", testName = 
"TemplateOptionsToStatementWithoutPublicKeyTest")
-public class TemplateOptionsToStatementWithoutPublicKeyTest {
-
-   @Test
-   public void 
testPublicKeyDoesNotGenerateAuthorizePublicKeyStatementIfOnlyPublicKeyOptionsConfigured()
 {
-      Map<String, String> keys = SshKeys.generate();
-      TemplateOptions options = 
TemplateOptions.Builder.authorizePublicKey(keys.get("public"));
-
-      TemplateOptionsToStatementWithoutPublicKey function = new 
TemplateOptionsToStatementWithoutPublicKey();
-      assertNull(function.apply(options));
-   }
-
-   @Test
-   public void 
testPublicAndRunScriptKeyDoesNotGenerateAuthorizePublicKeyStatementIfRunScriptPresent()
 {
-      Map<String, String> keys = SshKeys.generate();
-      TemplateOptions options = 
TemplateOptions.Builder.authorizePublicKey(keys.get("public")).runScript("uptime");
-
-      TemplateOptionsToStatementWithoutPublicKey function = new 
TemplateOptionsToStatementWithoutPublicKey();
-      Statement statement = function.apply(options);
-
-      assertEquals(statement.render(OsFamily.UNIX), "uptime\n");
-   }
-
-   @Test
-   public void 
testPublicAndPrivateKeyAndRunScriptDoesNotGenerateAuthorizePublicKeyStatementIfOtherOptionsPresent()
 {
-      Map<String, String> keys = SshKeys.generate();
-      TemplateOptions options = 
TemplateOptions.Builder.authorizePublicKey(keys.get("public"))
-            .installPrivateKey(keys.get("private")).runScript("uptime");
-
-      TemplateOptionsToStatementWithoutPublicKey function = new 
TemplateOptionsToStatementWithoutPublicKey();
-      Statement statement = function.apply(options);
-
-      assertTrue(statement instanceof StatementList);
-      StatementList statements = (StatementList) statement;
-
-      assertEquals(statements.size(), 2);
-      assertEquals(statements.get(0).render(OsFamily.UNIX), "uptime\n");
-      assertTrue(statements.get(1) instanceof InstallRSAPrivateKey);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java
----------------------------------------------------------------------
diff --git 
a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java
 
b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java
index fe48d66..4d12b86 100644
--- 
a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java
+++ 
b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java
@@ -231,7 +231,7 @@ public class UserAdd implements Statement {
       if (!authorizeRSAPublicKeys.isEmpty() || installRSAPrivateKey != null) {
          String sshDir = homeDir + "{fs}.ssh";
          if (!authorizeRSAPublicKeys.isEmpty())
-            statements.add(new AuthorizeRSAPublicKeys(sshDir, 
authorizeRSAPublicKeys));
+            statements.add(new AuthorizeRSAPublicKeys(sshDir, 
authorizeRSAPublicKeys, login));
          if (installRSAPrivateKey != null)
             statements.add(new InstallRSAPrivateKey(sshDir, 
installRSAPrivateKey));
       }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeys.java
----------------------------------------------------------------------
diff --git 
a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeys.java
 
b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeys.java
index 384a59e..13ec2dd 100644
--- 
a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeys.java
+++ 
b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeys.java
@@ -22,6 +22,7 @@ import static 
org.jclouds.scriptbuilder.domain.Statements.exec;
 
 import java.util.List;
 
+import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.scriptbuilder.domain.OsFamily;
 import org.jclouds.scriptbuilder.domain.Statement;
 import org.jclouds.scriptbuilder.domain.StatementList;
@@ -34,14 +35,20 @@ import com.google.common.collect.ImmutableList.Builder;
 public class AuthorizeRSAPublicKeys implements Statement {
    private final String sshDir;
    private final List<String> publicKeys;
-
+   private final String owner;
+   
    public AuthorizeRSAPublicKeys(Iterable<String> publicKeys) {
-      this("~/.ssh", publicKeys);
+      this("~/.ssh", publicKeys, null);
+   }
+   
+   public AuthorizeRSAPublicKeys(Iterable<String> publicKeys, @Nullable String 
owner) {
+      this("~/.ssh", publicKeys, owner);
    }
 
-   public AuthorizeRSAPublicKeys(String sshDir, Iterable<String> publicKeys) {
+   public AuthorizeRSAPublicKeys(String sshDir, Iterable<String> publicKeys, 
@Nullable String owner) {
       this.sshDir = checkNotNull(sshDir, "sshDir");
       this.publicKeys = ImmutableList.copyOf(checkNotNull(publicKeys, 
"publicKeys"));
+      this.owner = owner;
    }
 
    @Override
@@ -59,6 +66,9 @@ public class AuthorizeRSAPublicKeys implements Statement {
       String authorizedKeys = sshDir + "{fs}authorized_keys";
       statements.add(appendFile(authorizedKeys, 
Splitter.on('\n').split(Joiner.on("\n\n").join(publicKeys))));
       statements.add(exec("chmod 600 " + authorizedKeys));
+      if (owner != null) {
+         statements.add(exec(String.format("chown -R %s %s", owner, sshDir)));
+      }
       return new StatementList(statements.build()).render(family);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java
----------------------------------------------------------------------
diff --git 
a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java
 
b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java
index 76d64e6..f24022d 100644
--- 
a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java
+++ 
b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java
@@ -70,7 +70,7 @@ public class UserAddTest {
    public void testWithSshAuthorizedKeyUNIX() {
       assertEquals(
                
UserAdd.builder().login("me").authorizeRSAPublicKey("rsapublickey").build().render(OsFamily.UNIX),
-               "mkdir -p /home/users\nchmod 0755 /home/users\nuseradd -c me -s 
/bin/bash -m  -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> 
/home/users/me/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 
/home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n");
+               "mkdir -p /home/users\nchmod 0755 /home/users\nuseradd -c me -s 
/bin/bash -m  -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> 
/home/users/me/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 
/home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me/.ssh\nchown -R 
me /home/users/me\n");
    }
 
    public void testWithSshInstalledKeyUNIX() {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java
----------------------------------------------------------------------
diff --git 
a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java
 
b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java
index acc76a4..ba11e98 100644
--- 
a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java
+++ 
b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java
@@ -28,6 +28,17 @@ public class AuthorizeRSAPublicKeyTest {
 
    public void testAuthorizeRSAPublicKeyUNIXCurrentUser() {
       assertEquals(
+               new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB"), 
"jclouds").render(OsFamily.UNIX),
+               "mkdir -p ~/.ssh\n" +
+               "cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n" +
+               "\tssh-dss AAAAB\n" +
+               "END_OF_JCLOUDS_FILE\n" +
+               "chmod 600 ~/.ssh/authorized_keys\n" +
+               "chown -R jclouds ~/.ssh\n");
+   }
+   
+   public void testAuthorizeRSAPublicKeyUNIXNoOwner() {
+      assertEquals(
                new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss 
AAAAB")).render(OsFamily.UNIX),
                "mkdir -p ~/.ssh\n" +
                "cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n" +
@@ -38,29 +49,31 @@ public class AuthorizeRSAPublicKeyTest {
 
    public void testAuthorizeRSAPublicKeyUNIXCurrentUserWith2Keys() {
       assertEquals(
-               new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", 
"ssh-dss CCCCD")).render(OsFamily.UNIX),
+               new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", 
"ssh-dss CCCCD"), "jclouds").render(OsFamily.UNIX),
                "mkdir -p ~/.ssh\n" +
                "cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n" +
                "\tssh-dss AAAAB\n" +
                "\t\n" +
                "\tssh-dss CCCCD\n" +
                "END_OF_JCLOUDS_FILE\n" +
-               "chmod 600 ~/.ssh/authorized_keys\n");
+               "chmod 600 ~/.ssh/authorized_keys\n" +
+               "chown -R jclouds ~/.ssh\n");
    }
 
    public void testAuthorizeRSAPublicKeyUNIXSpecifiedDir() {
       assertEquals(
-               new AuthorizeRSAPublicKeys("/home/me/.ssh", 
ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX),
+               new AuthorizeRSAPublicKeys("/home/me/.ssh", 
ImmutableSet.of("ssh-dss AAAAB"), "jclouds").render(OsFamily.UNIX),
                "mkdir -p /home/me/.ssh\n" +
                "cat >> /home/me/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_FILE'\n" +
                "\tssh-dss AAAAB\n" +
                "END_OF_JCLOUDS_FILE\n" +
-               "chmod 600 /home/me/.ssh/authorized_keys\n");
+               "chmod 600 /home/me/.ssh/authorized_keys\n" +
+               "chown -R jclouds /home/me/.ssh\n");
    }
 
    public void testAuthorizeRSAPublicKeyUNIXSpecifiedDirWith2Keys() {
       assertEquals(
-               new AuthorizeRSAPublicKeys("/home/me/.ssh", 
ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD"))
+               new AuthorizeRSAPublicKeys("/home/me/.ssh", 
ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD"), "jclouds")
                         .render(OsFamily.UNIX),
                         "mkdir -p /home/me/.ssh\n" +
                               "cat >> /home/me/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_FILE'\n" +
@@ -68,11 +81,12 @@ public class AuthorizeRSAPublicKeyTest {
                               "\t\n" +
                               "\tssh-dss CCCCD\n" +
                               "END_OF_JCLOUDS_FILE\n" +
-                              "chmod 600 /home/me/.ssh/authorized_keys\n");
+                              "chmod 600 /home/me/.ssh/authorized_keys\n" +
+                              "chown -R jclouds /home/me/.ssh\n");
    }
 
    @Test(expectedExceptions = UnsupportedOperationException.class)
    public void testAuthorizeRSAPublicKeyWINDOWS() {
-      new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss 
AAAAB")).render(OsFamily.WINDOWS);
+      new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB"), 
"jclouds").render(OsFamily.WINDOWS);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh
----------------------------------------------------------------------
diff --git a/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh 
b/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh
index cd2695f..f2c6e04 100644
--- a/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh
+++ b/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh
@@ -15,6 +15,7 @@ cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys 
<<'END_OF_FILE'
 publicKey
 END_OF_FILE
 chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
+chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
 chown -R defaultAdminUsername /home/users/defaultAdminUsername
 exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
 PermitRootLogin no

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/test/resources/test_adminaccess_params.sh
----------------------------------------------------------------------
diff --git a/scriptbuilder/src/test/resources/test_adminaccess_params.sh 
b/scriptbuilder/src/test/resources/test_adminaccess_params.sh
index 42d4852..ee61aa6 100644
--- a/scriptbuilder/src/test/resources/test_adminaccess_params.sh
+++ b/scriptbuilder/src/test/resources/test_adminaccess_params.sh
@@ -14,6 +14,7 @@ cat >> /over/ridden/foo/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_FILE'
        fooPublicKey
 END_OF_JCLOUDS_FILE
 chmod 600 /over/ridden/foo/.ssh/authorized_keys
+chown -R foo /over/ridden/foo/.ssh
 chown -R foo /over/ridden/foo
 exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
 PermitRootLogin no

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh
----------------------------------------------------------------------
diff --git 
a/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh 
b/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh
index 20b1ee6..2ec9b27 100644
--- a/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh
+++ b/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh
@@ -14,6 +14,7 @@ cat >> /over/ridden/foo/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_FILE'
        fooPublicKey
 END_OF_JCLOUDS_FILE
 chmod 600 /over/ridden/foo/.ssh/authorized_keys
+chown -R foo /over/ridden/foo/.ssh
 chown -R foo /over/ridden/foo
 exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
 PermitRootLogin no

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh
----------------------------------------------------------------------
diff --git a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh 
b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh
index 5583ab4..1f5164c 100644
--- a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh
+++ b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh
@@ -6,6 +6,7 @@ cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_
        publicKey
 END_OF_JCLOUDS_FILE
 chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
+chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
 mkdir -p /home/users/defaultAdminUsername/.ssh
 rm /home/users/defaultAdminUsername/.ssh/id_rsa
 cat >> /home/users/defaultAdminUsername/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'

http://git-wip-us.apache.org/repos/asf/jclouds/blob/179ed3b2/scriptbuilder/src/test/resources/test_adminaccess_standard.sh
----------------------------------------------------------------------
diff --git a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh 
b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh
index db10e19..5e0c79d 100644
--- a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh
+++ b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh
@@ -14,6 +14,7 @@ cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys 
<<-'END_OF_JCLOUDS_
        publicKey
 END_OF_JCLOUDS_FILE
 chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
+chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
 chown -R defaultAdminUsername /home/users/defaultAdminUsername
 exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
 PermitRootLogin no

Reply via email to