Issue 915: supports AdminAccess.adminHome, and UserAdd.home

Previously, UserAdd only supported 'defaultHome'. Now it supports 
'home' as well. This involved changing the `mkdir` from making 
defaultHome to making the actual home (felt like easier 
production-code than getting the parent directory of 'home' to mkdir,
but turned out to be a lot of test-code changes!).

Added AdminAccess.adminHome, which is a direct pass-through to 
UserAdd.home.
This commit is contained in:
Aled Sage 2012-05-21 21:10:28 +01:00
parent 2fef9008eb
commit 8b6af79214
12 changed files with 79 additions and 34 deletions

View File

@ -126,7 +126,7 @@ public class RunScriptOnNodeUsingSshTest {
expect(sshClient.getUsername()).andReturn("tester");
expect(sshClient.getHostAddress()).andReturn("somewhere.example.com");
expect(
sshClient.exec("sudo sh <<'RUN_SCRIPT_AS_ROOT_SSH'\n" + "mkdir -p /home/users\n"
sshClient.exec("sudo sh <<'RUN_SCRIPT_AS_ROOT_SSH'\n" + "mkdir -p /home/users/testuser\n"
+ "useradd -s /bin/bash -m -d /home/users/testuser testuser\n"
+ "chown -R testuser /home/users/testuser\n" + "RUN_SCRIPT_AS_ROOT_SSH\n")).andReturn(
new ExecResponse("done", null, 0));

View File

@ -244,9 +244,9 @@ public abstract class BaseComputeServiceLiveTest extends BaseComputeServiceConte
checkNodes(nodes, group, "runScriptWithCreds");
// test adding AdminAccess later changes the default boot user, in this
// case to foo
// case to foo, with home dir /over/ridden/foo
ListenableFuture<ExecResponse> future = client.submitScriptOnNode(node.getId(), AdminAccess.builder()
.adminUsername("foo").build(), nameTask("adminUpdate"));
.adminUsername("foo").adminHome("/over/ridden/foo").build(), nameTask("adminUpdate"));
response = future.get(3, TimeUnit.MINUTES);

View File

@ -182,7 +182,7 @@ END_OF_JCLOUDS_SCRIPT
%wheel ALL = (ALL) NOPASSWD:ALL
END_OF_JCLOUDS_FILE
chmod 0440 /etc/sudoers
mkdir -p /home/users
mkdir -p /home/users/defaultAdminUsername
groupadd -f wheel
useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername
mkdir -p /home/users/defaultAdminUsername/.ssh

View File

@ -182,7 +182,7 @@ END_OF_JCLOUDS_SCRIPT
%wheel ALL = (ALL) NOPASSWD:ALL
END_OF_JCLOUDS_FILE
chmod 0440 /etc/sudoers
mkdir -p /home/users
mkdir -p /home/users/web
groupadd -f wheel
useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web
mkdir -p /home/users/web/.ssh

View File

@ -89,15 +89,15 @@ END_OF_JCLOUDS_SCRIPT
%wheel ALL = (ALL) NOPASSWD:ALL
END_OF_JCLOUDS_FILE
chmod 0440 /etc/sudoers
mkdir -p /home/users
mkdir -p /over/ridden/foo
groupadd -f wheel
useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo
mkdir -p /home/users/foo/.ssh
cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
useradd -s /bin/bash -g wheel -m -d /over/ridden/foo -p 'crypt(randompassword)' foo
mkdir -p /over/ridden/foo/.ssh
cat >> /over/ridden/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
publicKey
END_OF_JCLOUDS_FILE
chmod 600 /home/users/foo/.ssh/authorized_keys
chown -R foo /home/users/foo
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

View File

@ -109,6 +109,7 @@ public class AdminAccess implements Statement {
}
private String adminUsername;
private String adminHome;
private String adminPublicKey;
private File adminPublicKeyFile;
private String adminPrivateKey;
@ -126,6 +127,11 @@ public class AdminAccess implements Statement {
return this;
}
public AdminAccess.Builder adminHome(String adminHome) {
this.adminHome = adminHome;
return this;
}
public AdminAccess.Builder adminPassword(String adminPassword) {
this.adminPassword = adminPassword;
return this;
@ -197,8 +203,8 @@ public class AdminAccess implements Statement {
String adminPrivateKey = this.adminPrivateKey;
if (adminPrivateKey == null && adminPrivateKeyFile != null)
adminPrivateKey = Files.toString(adminPrivateKeyFile, UTF_8);
return new Config(adminUsername, adminPublicKey, adminPrivateKey, adminPassword, loginPassword, lockSsh,
grantSudoToAdminUser, authorizeAdminPublicKey, installAdminPrivateKey, resetLoginPassword,
return new Config(adminUsername, adminHome, adminPublicKey, adminPrivateKey, adminPassword, loginPassword,
lockSsh, grantSudoToAdminUser, authorizeAdminPublicKey, installAdminPrivateKey, resetLoginPassword,
cryptFunction);
} catch (IOException e) {
throw Throwables.propagate(e);
@ -208,6 +214,7 @@ public class AdminAccess implements Statement {
protected static class Config {
private final String adminUsername;
private final String adminHome;
private final String adminPublicKey;
private final String adminPrivateKey;
private final String adminPassword;
@ -220,11 +227,12 @@ public class AdminAccess implements Statement {
private final Function<String, String> cryptFunction;
private final Credentials adminCredentials;
protected Config(@Nullable String adminUsername, @Nullable String adminPublicKey,
protected Config(@Nullable String adminUsername, @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<String, String> cryptFunction) {
this.adminUsername = adminUsername;
this.adminHome = adminHome;
this.adminPublicKey = adminPublicKey;
this.adminPrivateKey = adminPrivateKey;
this.adminPassword = adminPassword;
@ -245,6 +253,10 @@ public class AdminAccess implements Statement {
return adminUsername;
}
public String getAdminHome() {
return adminHome;
}
public String getAdminPublicKey() {
return adminPublicKey;
}
@ -324,6 +336,7 @@ public class AdminAccess implements Statement {
Builder builder = AdminAccess.builder(configuration.cryptFunction());
builder.adminUsername(config.getAdminUsername() != null ? config.getAdminUsername() : configuration
.defaultAdminUsername().get());
builder.adminHome(config.getAdminHome());
builder.adminPassword(config.getAdminPassword() != null ? config.getAdminPassword() : configuration
.passwordGenerator().get());
Map<String, String> adminSshKeys = (config.getAdminPublicKey() != null && config.getAdminPrivateKey() != null) ? ImmutableMap
@ -363,6 +376,8 @@ public class AdminAccess implements Statement {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
UserAdd.Builder userBuilder = UserAdd.builder();
userBuilder.login(config.getAdminUsername());
if (config.getAdminHome() != null)
userBuilder.home(config.getAdminHome());
if (config.shouldAuthorizeAdminPublicKey())
userBuilder.authorizeRSAPublicKey(config.getAdminPublicKey());
userBuilder.password(config.getAdminPassword());

View File

@ -60,6 +60,7 @@ public class UserAdd implements Statement {
public static class Builder {
private String defaultHome = "/home/users";
private String home;
private String login;
private String password;
private String RSAPrivateKey;
@ -67,6 +68,17 @@ public class UserAdd implements Statement {
private List<String> authorizeRSAPublicKeys = Lists.newArrayList();
private String shell = "/bin/bash";
/**
* See --home in `man useradd`.
*/
public UserAdd.Builder home(String home) {
this.home = home;
return this;
}
/**
* See --base-dir in `man useradd`.
*/
public UserAdd.Builder defaultHome(String defaultHome) {
this.defaultHome = defaultHome;
return this;
@ -115,22 +127,29 @@ public class UserAdd implements Statement {
}
public UserAdd build() {
return new UserAdd(login, groups, password, RSAPrivateKey, authorizeRSAPublicKeys, defaultHome, shell);
return new UserAdd(login, groups, password, RSAPrivateKey, authorizeRSAPublicKeys, home, defaultHome, shell);
}
}
public UserAdd(String login, List<String> groups, @Nullable String password, @Nullable String installRSAPrivateKey,
List<String> authorizeRSAPublicKeys, String defaultHome, String shell) {
this(login, groups, password, installRSAPrivateKey, authorizeRSAPublicKeys, null, defaultHome, shell);
}
public UserAdd(String login, List<String> groups, @Nullable String password, @Nullable String installRSAPrivateKey,
List<String> authorizeRSAPublicKeys, @Nullable String home, String defaultHome, String shell) {
this.login = checkNotNull(login, "login");
this.password = password;
this.groups = ImmutableList.copyOf(checkNotNull(groups, "groups"));
this.installRSAPrivateKey = installRSAPrivateKey;
this.authorizeRSAPublicKeys = ImmutableList
.copyOf(checkNotNull(authorizeRSAPublicKeys, "authorizeRSAPublicKeys"));
this.home = home;
this.defaultHome = checkNotNull(defaultHome, "defaultHome");
this.shell = checkNotNull(shell, "shell");
}
private final String home;
private final String defaultHome;
private final String login;
private final List<String> groups;
@ -159,10 +178,10 @@ public class UserAdd implements Statement {
checkNotNull(family, "family");
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
String homeDir = defaultHome + "{fs}" + login;
String homeDir = (home != null) ? home : (defaultHome + "{fs}" + login);
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
// useradd cannot create the default homedir
statements.add(Statements.exec("{md} " + defaultHome));
statements.add(Statements.exec("{md} " + homeDir));
ImmutableMap.Builder<String, String> userAddOptions = ImmutableMap.builder();
userAddOptions.put("-s", shell);

View File

@ -52,8 +52,9 @@ public class AdminAccessTest {
try {
assertEquals(
AdminAccess.builder().adminPassword("bar").adminPrivateKey("fooPrivateKey")
.adminPublicKey("fooPublicKey").adminUsername("foo").build().init(TestConfiguration.INSTANCE)
.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(
.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();

View File

@ -33,41 +33,51 @@ public class UserAddTest {
public void testUNIX() {
assertEquals(UserAdd.builder().login("me").build().render(OsFamily.UNIX),
"mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nchown -R me /home/users/me\n");
"mkdir -p /home/users/me\nuseradd -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 -s /bin/bash -m -d /export/home/me me\nchown -R me /export/home/me\n");
"mkdir -p /export/home/me\nuseradd -s /bin/bash -m -d /export/home/me me\nchown -R me /export/home/me\n");
}
public void testWithGroupUNIX() {
assertEquals(UserAdd.builder().login("me").group("wheel").build().render(OsFamily.UNIX),
"mkdir -p /home/users\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me me\nchown -R me /home/users/me\n");
"mkdir -p /home/users/me\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me me\nchown -R me /home/users/me\n");
}
public void testWithGroupsUNIX() {
assertEquals(UserAdd.builder().login("me").groups(ImmutableList.of("wheel", "candy")).build().render(
OsFamily.UNIX),
"mkdir -p /home/users\ngroupadd -f wheel\ngroupadd -f candy\nuseradd -s /bin/bash -g wheel -G candy -m -d /home/users/me me\nchown -R me /home/users/me\n");
"mkdir -p /home/users/me\ngroupadd -f wheel\ngroupadd -f candy\nuseradd -s /bin/bash -g wheel -G candy -m -d /home/users/me me\nchown -R me /home/users/me\n");
}
public void testWithPasswordUNIX() {
String userAdd = UserAdd.builder().login("me").password("foo").group("wheel").build().render(OsFamily.UNIX);
assert userAdd.startsWith("mkdir -p /home/users\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me -p '$6$") : userAdd;
assert userAdd.startsWith("mkdir -p /home/users/me\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me -p '$6$") : userAdd;
assert userAdd.endsWith("' me\nchown -R me /home/users/me\n") : userAdd;
}
public void testWithSshAuthorizedKeyUNIX() {
assertEquals(
UserAdd.builder().login("me").authorizeRSAPublicKey("rsapublickey").build().render(OsFamily.UNIX),
"mkdir -p /home/users\nuseradd -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/me\nuseradd -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");
}
public void testWithSshInstalledKeyUNIX() {
assertEquals(
UserAdd.builder().login("me").installRSAPrivateKey("rsaprivate").build().render(OsFamily.UNIX),
"mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n\trsaprivate\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n");
"mkdir -p /home/users/me\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n\trsaprivate\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n");
}
public void testWithHomeUNIX() {
assertEquals(UserAdd.builder().login("me").home("/myhome/myme").build().render(
OsFamily.UNIX),
"mkdir -p /myhome/myme\nuseradd -s /bin/bash -m -d /myhome/myme me\nchown -R me /myhome/myme\n");
assertEquals(UserAdd.builder().login("me").home("/myhome/myme").defaultHome("/ignoreddefault").build().render(
OsFamily.UNIX),
"mkdir -p /myhome/myme\nuseradd -s /bin/bash -m -d /myhome/myme me\nchown -R me /myhome/myme\n");
}
@Test(expectedExceptions = UnsupportedOperationException.class)

View File

@ -3,15 +3,15 @@ cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL
END_OF_JCLOUDS_FILE
chmod 0440 /etc/sudoers
mkdir -p /home/users
mkdir -p /over/ridden/foo
groupadd -f wheel
useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(bar)' foo
mkdir -p /home/users/foo/.ssh
cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
useradd -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 /home/users/foo/.ssh/authorized_keys
chown -R foo /home/users/foo
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

View File

@ -1,4 +1,4 @@
mkdir -p /home/users
mkdir -p /home/users/defaultAdminUsername
useradd -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'

View File

@ -3,7 +3,7 @@ cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL
END_OF_JCLOUDS_FILE
chmod 0440 /etc/sudoers
mkdir -p /home/users
mkdir -p /home/users/defaultAdminUsername
groupadd -f wheel
useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername
mkdir -p /home/users/defaultAdminUsername/.ssh