diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java index 5b2b143888..9b8425fd9e 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java @@ -109,6 +109,7 @@ public class AdminAccess implements Statement { } private String adminUsername; + private String adminFullName; private String adminHome; private String adminPublicKey; private File adminPublicKeyFile; @@ -127,6 +128,12 @@ public class AdminAccess implements Statement { return this; } + public AdminAccess.Builder adminFullName(String adminFullName) { + this.adminFullName = adminFullName; + return this; + } + + public AdminAccess.Builder adminHome(String adminHome) { this.adminHome = adminHome; return this; @@ -211,7 +218,7 @@ public class AdminAccess implements Statement { String adminPrivateKey = this.adminPrivateKey; if (adminPrivateKey == null && adminPrivateKeyFile != null) adminPrivateKey = Files.toString(adminPrivateKeyFile, UTF_8); - return new Config(adminUsername, adminHome, adminPublicKey, adminPrivateKey, adminPassword, loginPassword, + return new Config(adminUsername, adminFullName, adminHome, adminPublicKey, adminPrivateKey, adminPassword, loginPassword, lockSsh, grantSudoToAdminUser, authorizeAdminPublicKey, installAdminPrivateKey, resetLoginPassword, cryptFunction); } catch (IOException e) { @@ -222,6 +229,7 @@ public class AdminAccess implements Statement { protected static class Config { private final String adminUsername; + private final String adminFullName; private final String adminHome; private final String adminPublicKey; private final String adminPrivateKey; @@ -235,11 +243,12 @@ public class AdminAccess implements Statement { private boolean authorizeAdminPublicKey; private boolean lockSsh; - protected Config(@Nullable String adminUsername, @Nullable String adminHome, @Nullable String adminPublicKey, + protected Config(@Nullable String adminUsername, @Nullable String adminFullName, @Nullable String adminHome, @Nullable String adminPublicKey, @Nullable String adminPrivateKey, @Nullable String adminPassword, @Nullable String loginPassword, boolean lockSsh, boolean grantSudoToAdminUser, boolean authorizeAdminPublicKey, boolean installAdminPrivateKey, boolean resetLoginPassword, Function cryptFunction) { this.adminUsername = adminUsername; + this.adminFullName = adminFullName; this.adminHome = adminHome; this.adminPublicKey = adminPublicKey; this.adminPrivateKey = adminPrivateKey; @@ -267,6 +276,10 @@ public class AdminAccess implements Statement { return adminUsername; } + public String getAdminFullName() { + return adminFullName; + } + public String getAdminHome() { return adminHome; } @@ -318,7 +331,8 @@ public class AdminAccess implements Statement { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("Config [adminUsername=").append(adminUsername).append(", adminHome=").append(adminHome) + builder.append("Config [adminUsername=").append(adminUsername).append(", adminFullName=").append(adminFullName) + .append(", adminHome=").append(adminHome) .append(", adminPublicKey=").append(adminPublicKey == null ? "null" : "present") .append(", adminPrivateKey=").append(adminPrivateKey == null ? "null" : "present") .append(", adminPassword=").append(adminPassword == null ? "null" : "present") @@ -368,6 +382,7 @@ public class AdminAccess implements Statement { Builder builder = AdminAccess.builder(configuration.cryptFunction()); builder.adminUsername(config.getAdminUsername() != null ? config.getAdminUsername() : configuration .defaultAdminUsername().get()); + builder.adminFullName(config.getAdminFullName() != null ? config.getAdminFullName() : builder.adminUsername); builder.adminHome(config.getAdminHome()); builder.adminPassword(config.getAdminPassword() != null ? config.getAdminPassword() : configuration .passwordGenerator().get()); @@ -408,6 +423,7 @@ public class AdminAccess implements Statement { ImmutableList.Builder statements = ImmutableList.builder(); UserAdd.Builder userBuilder = UserAdd.builder(); userBuilder.login(config.getAdminUsername()); + userBuilder.fullName(config.getAdminFullName()); if (config.getAdminHome() != null) userBuilder.home(config.getAdminHome()); if (config.shouldAuthorizeAdminPublicKey()) 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 b6a76b098b..e8b340bf9c 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 @@ -25,6 +25,7 @@ import java.util.List; import javax.inject.Named; +import com.google.common.base.*; import org.jclouds.crypto.Sha512Crypt; import org.jclouds.javax.annotation.Nullable; import org.jclouds.scriptbuilder.domain.OsFamily; @@ -35,14 +36,11 @@ import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys; import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.base.Objects; -import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.inject.Inject; +import org.jclouds.util.Strings2; /** * Creates a statement that will add a given user to a machine ("login"), with optional @@ -69,6 +67,7 @@ public class UserAdd implements Statement { private List groups = Lists.newArrayList(); private List authorizeRSAPublicKeys = Lists.newArrayList(); private String shell = "/bin/bash"; + private String fullName; /** * See --home in `man useradd`. @@ -128,18 +127,22 @@ public class UserAdd implements Statement { return this; } + public UserAdd.Builder fullName(String fullName) { + this.fullName = fullName; + return this; + } public UserAdd build() { - return new UserAdd(login, groups, password, RSAPrivateKey, authorizeRSAPublicKeys, home, defaultHome, shell); + return new UserAdd(login, groups, password, RSAPrivateKey, authorizeRSAPublicKeys, home, defaultHome, shell, fullName); } } public UserAdd(String login, List groups, @Nullable String password, @Nullable String installRSAPrivateKey, List authorizeRSAPublicKeys, String defaultHome, String shell) { - this(login, groups, password, installRSAPrivateKey, authorizeRSAPublicKeys, null, defaultHome, shell); + this(login, groups, password, installRSAPrivateKey, authorizeRSAPublicKeys, null, defaultHome, shell, login); } public UserAdd(String login, List groups, @Nullable String password, @Nullable String installRSAPrivateKey, - List authorizeRSAPublicKeys, @Nullable String home, String defaultHome, String shell) { + List authorizeRSAPublicKeys, @Nullable String home, String defaultHome, String shell, String fullName) { this.login = checkNotNull(login, "login"); this.password = password; this.groups = ImmutableList.copyOf(checkNotNull(groups, "groups")); @@ -149,6 +152,7 @@ public class UserAdd implements Statement { this.home = home; this.defaultHome = checkNotNull(defaultHome, "defaultHome"); this.shell = checkNotNull(shell, "shell"); + this.fullName = fullName; } private final String home; @@ -159,6 +163,7 @@ public class UserAdd implements Statement { private final String installRSAPrivateKey; private final List authorizeRSAPublicKeys; private final String shell; + private final String fullName; private Function cryptFunction = Sha512Crypt.function(); @@ -187,8 +192,13 @@ public class UserAdd implements Statement { ImmutableMap.Builder userAddOptions = ImmutableMap.builder(); // Include the username as the full name for now. - userAddOptions.put("-c", login); - + + if (Strings.isNullOrEmpty(fullName)) { + userAddOptions.put("-c", login); + } else { + userAddOptions.put("-c", "'" + fullName + "'"); + } + userAddOptions.put("-s", shell); if (groups.size() > 0) { for (String group : groups) diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java index 5c95ed3e11..64d0fbe714 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java @@ -52,15 +52,34 @@ public class AdminAccessTest { try { assertEquals( AdminAccess.builder().adminPassword("bar").adminPrivateKey("fooPrivateKey") - .adminPublicKey("fooPublicKey").adminUsername("foo").adminHome("/over/ridden/foo").build() + .adminPublicKey("fooPublicKey").adminUsername("foo") + .adminHome("/over/ridden/foo").build() .init(TestConfiguration.INSTANCE).render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( Resources.getResource("test_adminaccess_params.sh"), Charsets.UTF_8))); + } finally { TestConfiguration.INSTANCE.reset(); } } + public void testWithParamsAndFullNameUNIX() throws IOException { + TestConfiguration.INSTANCE.reset(); + try { + assertEquals( + AdminAccess.builder().adminPassword("bar").adminPrivateKey("fooPrivateKey") + .adminPublicKey("fooPublicKey").adminUsername("foo").adminFullName("JClouds Foo") + .adminHome("/over/ridden/foo").build() + .init(TestConfiguration.INSTANCE).render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_adminaccess_params_and_fullname.sh"), Charsets.UTF_8))); + + } finally { + TestConfiguration.INSTANCE.reset(); + } + } + + public void testOnlyInstallUserUNIX() throws IOException { TestConfiguration.INSTANCE.reset(); try { 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 27e2ac1f6c..81ee089ce1 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 @@ -20,6 +20,7 @@ package org.jclouds.scriptbuilder.statements.login; import static org.testng.Assert.assertEquals; +import org.jclouds.JcloudsVersion; import org.jclouds.scriptbuilder.domain.OsFamily; import org.testng.annotations.Test; @@ -36,6 +37,12 @@ public class UserAddTest { "mkdir -p /home/users\nuseradd -c me -s /bin/bash -m -d /home/users/me me\nchown -R me /home/users/me\n"); } + public void testWithFullNameUNIX() { + assertEquals(UserAdd.builder().login("me").fullName("JClouds Guy").build().render(OsFamily.UNIX), + "mkdir -p /home/users\nuseradd -c 'JClouds Guy' -s /bin/bash -m -d /home/users/me me\nchown -R me /home/users/me\n"); + + } + public void testWithBaseUNIX() { assertEquals(UserAdd.builder().login("me").defaultHome("/export/home").build().render(OsFamily.UNIX), "mkdir -p /export/home\nuseradd -c me -s /bin/bash -m -d /export/home/me me\nchown -R me /export/home/me\n"); diff --git a/scriptbuilder/src/test/resources/test_adminaccess_params.sh b/scriptbuilder/src/test/resources/test_adminaccess_params.sh index 123be324ce..f867d1f655 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_params.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_params.sh @@ -5,7 +5,7 @@ END_OF_JCLOUDS_FILE chmod 0440 /etc/sudoers mkdir -p /over/ridden groupadd -f wheel -useradd -c foo -s /bin/bash -g wheel -m -d /over/ridden/foo -p 'crypt(bar)' foo +useradd -c 'foo' -s /bin/bash -g wheel -m -d /over/ridden/foo -p 'crypt(bar)' foo mkdir -p /over/ridden/foo/.ssh cat >> /over/ridden/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' fooPublicKey diff --git a/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh b/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh new file mode 100644 index 0000000000..e01028faeb --- /dev/null +++ b/scriptbuilder/src/test/resources/test_adminaccess_params_and_fullname.sh @@ -0,0 +1,20 @@ +cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE' + root ALL = (ALL) ALL + %wheel ALL = (ALL) NOPASSWD:ALL +END_OF_JCLOUDS_FILE +chmod 0440 /etc/sudoers +mkdir -p /over/ridden +groupadd -f wheel +useradd -c 'JClouds Foo' -s /bin/bash -g wheel -m -d /over/ridden/foo -p 'crypt(bar)' foo +mkdir -p /over/ridden/foo/.ssh +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 +exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no +PermitRootLogin no +" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 +hash service 2>&- && service ssh reload 2>&- || /etc/init.d/ssh* reload +awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(0)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} +test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow diff --git a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh index f954fa83d1..39390063b6 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh @@ -1,5 +1,5 @@ mkdir -p /home/users -useradd -c defaultAdminUsername -s /bin/bash -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername +useradd -c 'defaultAdminUsername' -s /bin/bash -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername mkdir -p /home/users/defaultAdminUsername/.ssh cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' publicKey diff --git a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh index 5430a4ee41..34319c6396 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh @@ -5,7 +5,7 @@ END_OF_JCLOUDS_FILE chmod 0440 /etc/sudoers mkdir -p /home/users groupadd -f wheel -useradd -c defaultAdminUsername -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername +useradd -c 'defaultAdminUsername' -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername mkdir -p /home/users/defaultAdminUsername/.ssh cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' publicKey