Issue 473: created new function to add a user, and supporting sudoers and shadow logic

This commit is contained in:
Adrian Cole 2011-04-30 20:58:50 -07:00
parent 9388f8b5ca
commit 4b879402fd
20 changed files with 1172 additions and 77 deletions

View File

@ -57,4 +57,6 @@ public interface Crypto {
MessageDigest sha256();
MessageDigest sha512();
}

View File

@ -73,7 +73,8 @@ public class JCECrypto implements Crypto {
public final static String MD5 = "MD5";
public final static String SHA1 = "SHA1";
public final static String SHA256 = "SHA256";
public final static String SHA256 = "SHA-256";
public final static String SHA512 = "SHA-512";
@Override
public MessageDigest md5() {
@ -98,7 +99,16 @@ public class JCECrypto implements Crypto {
try {
return digest(SHA256);
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("SHA256 must be supported", e);
throw new IllegalStateException(SHA256 + " must be supported", e);
}
}
@Override
public MessageDigest sha512() {
try {
return digest(SHA512);
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(SHA512 + " must be supported", e);
}
}

View File

@ -45,7 +45,7 @@ import com.google.inject.Injector;
*
* @author Adrian Cole
*/
//NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "performance", sequential = true, timeOut = 2 * 60 * 1000, testName = "CryptoTest")
public class CryptoTest extends PerformanceTest {
@ -122,4 +122,15 @@ public class CryptoTest extends PerformanceTest {
assertEquals(hexMD5Digest, b64);
}
public void testSHA1() {
crypto.sha1();
}
public void testSHA256() {
crypto.sha256();
}
public void testSHA512() {
crypto.sha512();
}
}

View File

@ -36,15 +36,10 @@
<jclouds.test.listener></jclouds.test.listener>
</properties>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>r09</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>1.3.9</version>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -19,37 +19,21 @@
package org.jclouds.scriptbuilder.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import java.util.Collections;
import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
*
* @author Adrian Cole
* @see AuthorizeRSAPublicKeys
*/
public class AuthorizeRSAPublicKey implements Statement {
private final String publicKey;
@Deprecated
public class AuthorizeRSAPublicKey extends AuthorizeRSAPublicKeys {
public AuthorizeRSAPublicKey(String publicKey) {
this.publicKey = checkNotNull(publicKey, "publicKey");
super(ImmutableSet.of(checkNotNull(publicKey, "publicKey")));
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return Collections.emptyList();
}
@Override
public String render(OsFamily family) {
checkNotNull(family, "family");
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
return new StatementList(ImmutableList.of(exec("{md} ~/.ssh"), appendFile("~/.ssh/authorized_keys", Splitter.on('\n')
.split(publicKey)), exec("chmod 600 ~/.ssh/authorized_keys"))).render(family);
}
}

View File

@ -18,39 +18,15 @@
*/
package org.jclouds.scriptbuilder.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import static org.jclouds.scriptbuilder.domain.Statements.rm;
import java.util.Collections;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
/**
*
* @see org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey
* @author Adrian Cole
*/
public class InstallRSAPrivateKey implements Statement {
private final String privateKey;
@Deprecated
public class InstallRSAPrivateKey extends org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey {
public InstallRSAPrivateKey(String privateKey) {
this.privateKey = checkNotNull(privateKey, "privateKey");
super(privateKey);
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return Collections.emptyList();
}
@Override
public String render(OsFamily family) {
checkNotNull(family, "family");
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
return new StatementList(ImmutableList.of(exec("{md} ~/.ssh"), rm("~/.ssh/id_rsa"), appendFile("~/.ssh/id_rsa", Splitter.on('\n')
.split(privateKey)), exec("chmod 600 ~/.ssh/id_rsa"))).render(family);
}
}

View File

@ -0,0 +1,36 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.login;
import org.jclouds.scriptbuilder.domain.Statement;
/**
* Statements used in sudo control
*
* @author Adrian Cole
*/
public class SudoStatements {
/**
* create new sudoers file with the wheel group authorized to all commands without a password
*/
public static Statement createWheel() {
return new Sudoers();
}
}

View File

@ -0,0 +1,58 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.login;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableList.Builder;
/**
* Control /etc/sudoers
*
* @author Adrian Cole
*/
@Beta
public class Sudoers implements Statement {
private static final String sudoers = "/etc/sudoers";
public String render(OsFamily family) {
checkNotNull(family, "family");
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
Builder<Statement> statements = ImmutableList.<Statement> builder();
statements.add(exec("{rm} " + sudoers));
statements.add(appendFile(sudoers, ImmutableSet.of("root ALL = (ALL) ALL", "%wheel ALL = (ALL) NOPASSWD:ALL")));
statements.add(exec("chmod 0440 " + sudoers));
return new StatementList(statements.build()).render(family);
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return ImmutableList.of();
}
}

View File

@ -0,0 +1,205 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.login;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import javax.annotation.Nullable;
import org.jclouds.encryption.internal.JCECrypto;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
import org.jclouds.scriptbuilder.util.Sha512Crypt;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
/**
*
* @author Adrian Cole
*/
public class UserAdd implements Statement {
public static UserAdd.Builder builder() {
return new Builder();
}
public static class Builder {
private String defaultHome = "/home/users";
private String login;
private String password;
private String RSAPrivateKey;
private List<String> groups = Lists.newArrayList();
private List<String> authorizeRSAPublicKeys = Lists.newArrayList();
private String shell = "/bin/bash";
public UserAdd.Builder defaultHome(String defaultHome) {
this.defaultHome = defaultHome;
return this;
}
public UserAdd.Builder login(String login) {
this.login = login;
return this;
}
public UserAdd.Builder password(String password) {
this.password = password;
return this;
}
public UserAdd.Builder group(String group) {
this.groups.add(checkNotNull(group, "group"));
return this;
}
public UserAdd.Builder groups(Iterable<String> groups) {
this.groups = ImmutableList.<String> copyOf(checkNotNull(groups, "groups"));
return this;
}
public UserAdd.Builder installRSAPrivateKey(String RSAPrivateKey) {
this.RSAPrivateKey = RSAPrivateKey;
return this;
}
public UserAdd.Builder authorizeRSAPublicKey(String RSAPublicKey) {
this.authorizeRSAPublicKeys.add(checkNotNull(RSAPublicKey, "RSAPublicKey"));
return this;
}
public UserAdd.Builder authorizeRSAPublicKeys(Iterable<String> RSAPublicKeys) {
this.authorizeRSAPublicKeys = ImmutableList.<String> copyOf(checkNotNull(RSAPublicKeys, "RSAPublicKeys"));
return this;
}
public UserAdd.Builder shell(String shell) {
this.shell = shell;
return this;
}
public UserAdd build() {
return new UserAdd(login, groups, password, RSAPrivateKey, authorizeRSAPublicKeys, defaultHome, shell);
}
}
public UserAdd(String login, List<String> groups, @Nullable String password, @Nullable String installRSAPrivateKey,
List<String> authorizeRSAPublicKeys, 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.defaultHome = checkNotNull(defaultHome, "defaultHome");
this.shell = checkNotNull(shell, "shell");
}
private final String defaultHome;
private final String login;
private final List<String> groups;
private final String password;
private final String installRSAPrivateKey;
private final List<String> authorizeRSAPublicKeys;
private final String shell;
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return ImmutableList.of();
}
@Override
public String render(OsFamily family) {
checkNotNull(family, "family");
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
String homeDir = defaultHome + "{fs}" + login;
ImmutableList.Builder<Statement> statements = ImmutableList.<Statement> builder();
statements.add(Statements.exec("{md} " + homeDir));
ImmutableMap.Builder<String, String> userAddOptions = ImmutableMap.<String, String> builder();
userAddOptions.put("-s", shell);
if (groups.size() > 0) {
for (String group : groups)
statements.add(Statements.exec("groupadd -f " + group));
List<String> groups = Lists.newArrayList(this.groups);
String primaryGroup = groups.remove(0);
userAddOptions.put("-g", primaryGroup);
if (groups.size() > 0)
userAddOptions.put("-G", Joiner.on(',').join(groups));
}
userAddOptions.put("-d", homeDir);
if (password != null) {
try {
userAddOptions.put("-p", "'" + Sha512Crypt.makeShadowLine(password, null, new JCECrypto()) + "'");
} catch (Exception e) {
Throwables.propagate(e);
}
}
String options = Joiner.on(' ').withKeyValueSeparator(" ").join(userAddOptions.build());
statements.add(Statements.exec(String.format("useradd %s %s", options, login)));
if (authorizeRSAPublicKeys.size() > 0 || installRSAPrivateKey != null) {
String sshDir = homeDir + "{fs}.ssh";
if (authorizeRSAPublicKeys.size() > 0)
statements.add(new AuthorizeRSAPublicKeys(sshDir, authorizeRSAPublicKeys));
if (installRSAPrivateKey != null)
statements.add(new InstallRSAPrivateKey(sshDir, installRSAPrivateKey));
}
statements.add(Statements.exec(String.format("chown -R %s %s", login, homeDir)));
return new StatementList(statements.build()).render(family);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((login == null) ? 0 : login.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserAdd other = (UserAdd) obj;
if (login == null) {
if (other.login != null)
return false;
} else if (!login.equals(other.login))
return false;
return true;
}
}

View File

@ -0,0 +1,71 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.ssh;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import java.util.Collections;
import java.util.List;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
/**
*
* @author Adrian Cole
*/
public class AuthorizeRSAPublicKeys implements Statement {
private final String sshDir;
private final List<String> publicKeys;
public AuthorizeRSAPublicKeys(Iterable<String> publicKeys) {
this("~/.ssh", publicKeys);
}
public AuthorizeRSAPublicKeys(String sshDir, Iterable<String> publicKeys) {
this.sshDir = checkNotNull(sshDir, "sshDir");
this.publicKeys = ImmutableList.copyOf(checkNotNull(publicKeys, "publicKeys"));
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return Collections.emptyList();
}
@Override
public String render(OsFamily family) {
checkNotNull(family, "family");
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
Builder<Statement> statements = ImmutableList.<Statement> builder();
statements.add(exec("mkdir -p " + sshDir));
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));
return new StatementList(statements.build()).render(family);
}
}

View File

@ -0,0 +1,70 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.ssh;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import java.util.Collections;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
/**
*
* @author Adrian Cole
*/
public class InstallRSAPrivateKey implements Statement {
private final String sshDir;
private final String privateKey;
public InstallRSAPrivateKey(String privateKey) {
this("~/.ssh", privateKey);
}
public InstallRSAPrivateKey(String sshDir, String privateKey) {
this.sshDir = checkNotNull(sshDir, "sshDir");
this.privateKey = checkNotNull(privateKey, "privateKey");
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return Collections.emptyList();
}
@Override
public String render(OsFamily family) {
checkNotNull(family, "family");
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
Builder<Statement> statements = ImmutableList.<Statement> builder();
statements.add(exec("{md} " + sshDir));
String idRsa = sshDir + "{fs}id_rsa";
statements.add(exec("{rm} " + idRsa));
statements.add(appendFile(idRsa, Splitter.on('\n').split(privateKey)));
statements.add(exec("chmod 600 " + idRsa));
return new StatementList(statements.build()).render(family);
}
}

View File

@ -0,0 +1,44 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.ssh;
import java.util.Map;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.collect.ImmutableMap;
/**
* Statements used in ssh control
*
* @author Adrian Cole
*/
public class SshStatements {
/**
* lock sshd down so root cannot login, and password auth is disabled,
*/
public static Statement lockSshd() {
return sshdConfig(ImmutableMap.of("PasswordAuthentication","no", "PermitRootLogin","no"));
}
public static Statement sshdConfig(Map<String, String> params) {
return new SshdConfig(params);
}
}

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.ssh;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import java.util.Map;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
/**
* Control sshd_config
*
* @author Adrian Cole
*/
public class SshdConfig implements Statement {
private static final String sshdConfig = "/etc/ssh/sshd_config";
private final Map<String, String> params;
public SshdConfig(Map<String, String> params) {
this.params = checkNotNull(params, "params");
}
public String render(OsFamily family) {
String linesToPrepend = Joiner.on('\n').withKeyValueSeparator(" ").join(params);
Statement prependSshdConfig = exec(String.format(
"exec 3<> %1$s && awk -v TEXT=\"%2$s\n\" 'BEGIN {print TEXT}{print}' %1$s >&3", sshdConfig,
linesToPrepend));
Statement reloadSshdConfig = exec("/etc/init.d/sshd reload||/etc/init.d/ssh reload");
return newStatementList(prependSshdConfig, reloadSshdConfig).render(family);
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return ImmutableList.of();
}
}

View File

@ -0,0 +1,295 @@
/*
Sha512Crypt.java
Created: 18 December 2007
Last Changed By: $Author: broccol $
Version: $Revision: 7692 $
Last Mod Date: $Date: 2007-12-30 01:55:31 -0600 (Sun, 30 Dec 2007) $
Java Port By: James Ratcliff, falazar@arlut.utexas.edu
This class implements the new generation, scalable, SHA512-based
Unix 'crypt' algorithm developed by a group of engineers from Red
Hat, Sun, IBM, and HP for common use in the Unix and Linux
/etc/shadow files.
The Linux glibc library (starting at version 2.7) includes support
for validating passwords hashed using this algorithm.
The algorithm itself was released into the Public Domain by Ulrich
Drepper <drepper@redhat.com>. A discussion of the rationale and
development of this algorithm is at
http://people.redhat.com/drepper/sha-crypt.html
and the specification and a sample C language implementation is at
http://people.redhat.com/drepper/SHA-crypt.txt
This Java Port is
Copyright (c) 2008 The University of Texas at Austin.
All rights reserved.
Redistribution and use in source and binary form are permitted
provided that distributions retain this entire copyright notice
and comment. Neither the name of the University nor the names of
its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE.
*/
package org.jclouds.scriptbuilder.util;
import java.security.MessageDigest;
import javax.annotation.Nullable;
import org.jclouds.crypto.Crypto;
/**
* This class defines a method,
* {@link Sha512Crypt#Sha512_crypt(java.lang.String, java.lang.String, int) Sha512_crypt()}, which
* takes a password and a salt string and generates a Sha512 encrypted password entry.
*
* This class implements the new generation, scalable, SHA512-based Unix 'crypt' algorithm developed
* by a group of engineers from Red Hat, Sun, IBM, and HP for common use in the Unix and Linux
* /etc/shadow files.
*
* The Linux glibc library (starting at version 2.7) includes support for validating passwords
* hashed using this algorithm.
*
* The algorithm itself was released into the Public Domain by Ulrich Drepper
* &lt;drepper@redhat.com&gt;. A discussion of the rationale and development of this algorithm is at
*
* http://people.redhat.com/drepper/sha-crypt.html
*
* and the specification and a sample C language implementation is at
*
* http://people.redhat.com/drepper/SHA-crypt.txt
*/
public class Sha512Crypt {
static private final String sha512_salt_prefix = "$6$";
static private final String sha512_rounds_prefix = "rounds=";
static private final int SALT_LEN_MAX = 16;
static private final int ROUNDS_DEFAULT = 5000;
static private final int ROUNDS_MIN = 1000;
static private final int ROUNDS_MAX = 999999999;
static private final String SALTCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
static private final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/**
* This method actually generates an Sha512 crypted password hash from a plaintext password and a
* salt.
*
* <p>
* The resulting string will be in the form '$6$&lt;rounds=n&gt;$&lt;salt&gt;$&lt;hashed mess&gt;
* </p>
*
* @param password
* Plaintext password
*
* @param shadowPrefix
* An encoded salt/rounds which will be consulted to determine the salt and round
* count, if not null
*
* @return The Sha512 Unix Crypt hash text for the password
*/
public static String makeShadowLine(String password, @Nullable String shadowPrefix, Crypto crypto) {
MessageDigest ctx = crypto.sha512();
MessageDigest alt_ctx = crypto.sha512();
byte[] alt_result;
byte[] temp_result;
byte[] p_bytes = null;
byte[] s_bytes = null;
int cnt, cnt2;
int rounds = ROUNDS_DEFAULT; // Default number of rounds.
StringBuffer buffer;
/* -- */
if (shadowPrefix != null) {
if (shadowPrefix.startsWith(sha512_salt_prefix)) {
shadowPrefix = shadowPrefix.substring(sha512_salt_prefix.length());
}
if (shadowPrefix.startsWith(sha512_rounds_prefix)) {
String num = shadowPrefix.substring(sha512_rounds_prefix.length(), shadowPrefix.indexOf('$'));
int srounds = Integer.valueOf(num).intValue();
shadowPrefix = shadowPrefix.substring(shadowPrefix.indexOf('$') + 1);
rounds = Math.max(ROUNDS_MIN, Math.min(srounds, ROUNDS_MAX));
}
if (shadowPrefix.length() > SALT_LEN_MAX) {
shadowPrefix = shadowPrefix.substring(0, SALT_LEN_MAX);
}
} else {
java.util.Random randgen = new java.util.Random();
StringBuffer saltBuf = new StringBuffer();
while (saltBuf.length() < 16) {
int index = (int) (randgen.nextFloat() * SALTCHARS.length());
saltBuf.append(SALTCHARS.substring(index, index + 1));
}
shadowPrefix = saltBuf.toString();
}
byte[] key = password.getBytes();
byte[] salts = shadowPrefix.getBytes();
ctx.reset();
ctx.update(key, 0, key.length);
ctx.update(salts, 0, salts.length);
alt_ctx.reset();
alt_ctx.update(key, 0, key.length);
alt_ctx.update(salts, 0, salts.length);
alt_ctx.update(key, 0, key.length);
alt_result = alt_ctx.digest();
for (cnt = key.length; cnt > 64; cnt -= 64) {
ctx.update(alt_result, 0, 64);
}
ctx.update(alt_result, 0, cnt);
for (cnt = key.length; cnt > 0; cnt >>= 1) {
if ((cnt & 1) != 0) {
ctx.update(alt_result, 0, 64);
} else {
ctx.update(key, 0, key.length);
}
}
alt_result = ctx.digest();
alt_ctx.reset();
for (cnt = 0; cnt < key.length; ++cnt) {
alt_ctx.update(key, 0, key.length);
}
temp_result = alt_ctx.digest();
p_bytes = new byte[key.length];
for (cnt2 = 0, cnt = p_bytes.length; cnt >= 64; cnt -= 64) {
System.arraycopy(temp_result, 0, p_bytes, cnt2, 64);
cnt2 += 64;
}
System.arraycopy(temp_result, 0, p_bytes, cnt2, cnt);
alt_ctx.reset();
for (cnt = 0; cnt < 16 + (alt_result[0] & 0xFF); ++cnt) {
alt_ctx.update(salts, 0, salts.length);
}
temp_result = alt_ctx.digest();
s_bytes = new byte[salts.length];
for (cnt2 = 0, cnt = s_bytes.length; cnt >= 64; cnt -= 64) {
System.arraycopy(temp_result, 0, s_bytes, cnt2, 64);
cnt2 += 64;
}
System.arraycopy(temp_result, 0, s_bytes, cnt2, cnt);
/*
* Repeatedly run the collected hash value through SHA512 to burn CPU cycles.
*/
for (cnt = 0; cnt < rounds; ++cnt) {
ctx.reset();
if ((cnt & 1) != 0) {
ctx.update(p_bytes, 0, key.length);
} else {
ctx.update(alt_result, 0, 64);
}
if (cnt % 3 != 0) {
ctx.update(s_bytes, 0, salts.length);
}
if (cnt % 7 != 0) {
ctx.update(p_bytes, 0, key.length);
}
if ((cnt & 1) != 0) {
ctx.update(alt_result, 0, 64);
} else {
ctx.update(p_bytes, 0, key.length);
}
alt_result = ctx.digest();
}
buffer = new StringBuffer(sha512_salt_prefix);
if (rounds != 5000) {
buffer.append(sha512_rounds_prefix);
buffer.append(rounds);
buffer.append("$");
}
buffer.append(shadowPrefix);
buffer.append("$");
buffer.append(b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4));
buffer.append(b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4));
buffer.append(b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4));
buffer.append(b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4));
buffer.append(b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4));
buffer.append(b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4));
buffer.append(b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4));
buffer.append(b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4));
buffer.append(b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4));
buffer.append(b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4));
buffer.append(b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4));
buffer.append(b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4));
buffer.append(b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4));
buffer.append(b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4));
buffer.append(b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4));
buffer.append(b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4));
buffer.append(b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4));
buffer.append(b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4));
buffer.append(b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4));
buffer.append(b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4));
buffer.append(b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4));
buffer.append(b64_from_24bit((byte) 0x00, (byte) 0x00, alt_result[63], 2));
/*
* Clear the buffer for the intermediate result so that people attaching to processes or
* reading core dumps cannot get any information.
*/
ctx.reset();
return buffer.toString();
}
private static final String b64_from_24bit(byte B2, byte B1, byte B0, int size) {
int v = ((((int) B2) & 0xFF) << 16) | ((((int) B1) & 0xFF) << 8) | ((int) B0 & 0xff);
StringBuffer result = new StringBuffer();
while (--size >= 0) {
result.append(itoa64.charAt((int) (v & 0x3f)));
v >>>= 6;
}
return result.toString();
}
}

View File

@ -16,27 +16,27 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.scriptbuilder.domain;
package org.jclouds.scriptbuilder.statements.login;
import static org.testng.Assert.assertEquals;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class AuthorizeRSAPublicKeyTest {
public class SudoStatementsTest {
AuthorizeRSAPublicKey auth = new AuthorizeRSAPublicKey("ssh-dss AAAAB");
public void testAuthorizeRSAPublicKeyUNIX() {
public void testCreateWheelUNIX() {
assertEquals(
auth.render(OsFamily.UNIX),
"mkdir -p ~/.ssh\ncat >> ~/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\nEND_OF_FILE\nchmod 600 ~/.ssh/authorized_keys\n"); }
SudoStatements.createWheel().render(OsFamily.UNIX),
"rm /etc/sudoers\ncat >> /etc/sudoers <<'END_OF_FILE'\nroot ALL = (ALL) ALL\n%wheel ALL = (ALL) NOPASSWD:ALL\nEND_OF_FILE\nchmod 0440 /etc/sudoers\n");
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testAuthorizeRSAPublicKeyWINDOWS() {
auth.render(OsFamily.WINDOWS);
public void testCreateWheelWindowsNotSupported() {
SudoStatements.createWheel().render(OsFamily.WINDOWS);
}
}

View File

@ -0,0 +1,77 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.login;
import static org.testng.Assert.assertEquals;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class UserAddTest {
public void testUNIX() {
assertEquals(UserAdd.builder().login("me").build().render(OsFamily.UNIX),
"mkdir -p /home/users/me\nuseradd -s /bin/bash -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/me\nuseradd -s /bin/bash -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/me\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -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/me\ngroupadd -f wheel\ngroupadd -f candy\nuseradd -s /bin/bash -g wheel -G candy -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/me\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -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/me\nuseradd -s /bin/bash -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<'END_OF_FILE'\nrsapublickey\nEND_OF_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/me\nuseradd -s /bin/bash -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_FILE'\nrsaprivate\nEND_OF_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n");
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testAddUserWindowsNotSupported() {
UserAdd.builder().login("me").build().render(OsFamily.WINDOWS);
}
}

View File

@ -0,0 +1,63 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.ssh;
import static org.testng.Assert.assertEquals;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class AuthorizeRSAPublicKeyTest {
public void testAuthorizeRSAPublicKeyUNIXCurrentUser() {
assertEquals(
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX),
"mkdir -p ~/.ssh\ncat >> ~/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\nEND_OF_FILE\nchmod 600 ~/.ssh/authorized_keys\n");
}
public void testAuthorizeRSAPublicKeyUNIXCurrentUserWith2Keys() {
assertEquals(
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD")).render(OsFamily.UNIX),
"mkdir -p ~/.ssh\ncat >> ~/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\n\nssh-dss CCCCD\nEND_OF_FILE\nchmod 600 ~/.ssh/authorized_keys\n");
}
public void testAuthorizeRSAPublicKeyUNIXSpecifiedDir() {
assertEquals(
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX),
"mkdir -p /home/me/.ssh\ncat >> /home/me/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\nEND_OF_FILE\nchmod 600 /home/me/.ssh/authorized_keys\n");
}
public void testAuthorizeRSAPublicKeyUNIXSpecifiedDirWith2Keys() {
assertEquals(
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD"))
.render(OsFamily.UNIX),
"mkdir -p /home/me/.ssh\ncat >> /home/me/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\n\nssh-dss CCCCD\nEND_OF_FILE\nchmod 600 /home/me/.ssh/authorized_keys\n");
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testAuthorizeRSAPublicKeyWINDOWS() {
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.WINDOWS);
}
}

View File

@ -16,10 +16,11 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.scriptbuilder.domain;
package org.jclouds.scriptbuilder.statements.ssh;
import static org.testng.Assert.assertEquals;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.testng.annotations.Test;
/**
@ -28,16 +29,23 @@ import org.testng.annotations.Test;
@Test(groups = "unit")
public class InstallRSAPrivateKeyTest {
InstallRSAPrivateKey key = new InstallRSAPrivateKey("-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n");
public void testInstallRSAPrivateKeyUNIX() {
public void testInstallRSAPrivateKeyUNIXCurrentUser() {
assertEquals(
key.render(OsFamily.UNIX),
new InstallRSAPrivateKey("-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n")
.render(OsFamily.UNIX),
"mkdir -p ~/.ssh\nrm ~/.ssh/id_rsa\ncat >> ~/.ssh/id_rsa <<'END_OF_FILE'\n-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n\nEND_OF_FILE\nchmod 600 ~/.ssh/id_rsa\n");
}
public void testInstallRSAPrivateKeyUNIXSpecifiedHome() {
assertEquals(
new InstallRSAPrivateKey("/home/me/.ssh", "-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n")
.render(OsFamily.UNIX),
"mkdir -p /home/me/.ssh\nrm /home/me/.ssh/id_rsa\ncat >> /home/me/.ssh/id_rsa <<'END_OF_FILE'\n-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n\nEND_OF_FILE\nchmod 600 /home/me/.ssh/id_rsa\n");
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testInstallRSAPrivateKeyWINDOWS() {
key.render(OsFamily.WINDOWS);
new InstallRSAPrivateKey("-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n")
.render(OsFamily.WINDOWS);
}
}

View File

@ -0,0 +1,52 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.statements.ssh;
import static org.testng.Assert.assertEquals;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.statements.ssh.SshStatements;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class SshStatementsTest {
public void testLockSshdUNIX() {
assertEquals(SshStatements.lockSshd().render(OsFamily.UNIX), new StringBuilder().append(
"exec 3<> /etc/ssh/sshd_config && awk -v TEXT=\"")//
.append("PasswordAuthentication no").append("\n")//
.append("PermitRootLogin no").append("\n")//
.append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")//
.append("/etc/init.d/sshd reload||/etc/init.d/ssh reload").append("\n").toString());
}
public void testSshdConfigUNIX() {
assertEquals(SshStatements.sshdConfig(ImmutableMap.of("AddressFamily", "inet6")).render(OsFamily.UNIX),
new StringBuilder().append("exec 3<> /etc/ssh/sshd_config && awk -v TEXT=\"")//
.append("AddressFamily inet6").append("\n")//
.append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")//
.append("/etc/init.d/sshd reload||/etc/init.d/ssh reload").append("\n").toString());
}
}

View File

@ -0,0 +1,78 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.scriptbuilder.util;
import static org.testng.Assert.assertEquals;
import org.jclouds.crypto.Crypto;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class Sha512CryptTest {
protected Crypto crypto;
@BeforeTest
protected void createCrypto() {
Injector i = Guice.createInjector();
crypto = i.getInstance(Crypto.class);
}
public final static Object[][] TEST_DATA = {
{ "Hello world!", "$6$saltstring",
"$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1" },
{
"Hello world!",
"$6$rounds=10000$saltstringsaltstring",
"$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." },
{ "This is just a test", "$6$rounds=5000$toolongsaltstring",
"$6$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQzQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" },
{
"a very much longer text to encrypt. This one even stretches over morethan one line.",
"$6$rounds=1400$anotherlongsaltstring",
"$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wPvMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1" },
{
"a short string",
"$6$rounds=123456$asaltof16chars..",
"$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" },
{ "the minimum number is still observed", "$6$rounds=10$roundstoolow",
"$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1xhLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." } };
@DataProvider(name = "data")
public Object[][] createData1() {
return TEST_DATA;
}
/**
* Validate our implementation using test data from Ulrich Drepper's C implementation.
*/
@Test(dataProvider = "data")
public void testMakeCryptedPasswordHash(String password, String salt, String expected) {
assertEquals(Sha512Crypt.makeShadowLine(password, salt, crypto), expected);
}
}