You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2011/12/02 20:52:40 UTC
svn commit: r1209662 [3/3] - in /shiro/trunk: ./
core/src/main/java/org/apache/shiro/authc/credential/
core/src/main/java/org/apache/shiro/codec/
core/src/main/java/org/apache/shiro/config/
core/src/main/java/org/apache/shiro/crypto/ core/src/main/java...
Modified: shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/Hasher.java
URL: http://svn.apache.org/viewvc/shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/Hasher.java?rev=1209662&r1=1209661&r2=1209662&view=diff
==============================================================================
--- shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/Hasher.java (original)
+++ shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/Hasher.java Fri Dec 2 19:52:37 2011
@@ -24,6 +24,7 @@ import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.UnknownAlgorithmException;
import org.apache.shiro.crypto.hash.SimpleHash;
+import org.apache.shiro.crypto.hash.format.*;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.JavaEnvironment;
@@ -46,28 +47,30 @@ import java.util.Arrays;
*/
public final class Hasher {
- private static final Option ALGORITHM = new Option("a", "algorithm", true, "hash algorithm name. Defaults to MD5.");
+ private static final Option ALGORITHM = new Option("a", "algorithm", true, "hash algorithm name. Defaults to MD5 (SHA-256 when password hashing).");
private static final Option DEBUG = new Option("d", "debug", false, "show additional error (stack trace) information.");
+ private static final Option FORMAT = new Option("f", "format", true, "hash output format. Defaults to 'shiro1' when password hashing, 'hex' otherwise. See below for more information.");
private static final Option HELP = new Option("help", "help", false, "show this help message.");
- private static final Option HEX = new Option("h", "hex", false, "display a hex value instead of Base64.");
- private static final Option ITERATIONS = new Option("i", "iterations", true, "number of hash iterations. Defaults to 1.");
- private static final Option NO_FORMAT = new Option("nf", "noformat", false, "turn off output formatting. Any generated salt will be placed after the hash separated by a space.");
+ private static final Option ITERATIONS = new Option("i", "iterations", true, "number of hash iterations. Defaults to 350,000 when password hashing, 1 otherwise.");
private static final Option PASSWORD = new Option("p", "password", false, "hash a password (disable typing echo)");
private static final Option PASSWORD_NC = new Option("pnc", "pnoconfirm", false, "hash a password (disable typing echo) but disable password confirmation prompt.");
private static final Option RESOURCE = new Option("r", "resource", false, "read and hash the resource located at <value>. See below for more information.");
private static final Option SALT = new Option("s", "salt", true, "use the specified salt. <arg> is plaintext.");
private static final Option SALT_BYTES = new Option("sb", "saltbytes", true, "use the specified salt bytes. <arg> is hex or base64 encoded text.");
private static final Option SALT_GEN = new Option("gs", "gensalt", false, "generate and use a random salt.");
- private static final Option SALT_GEN_HEX = new Option("gsh", "gensalthex", false, "display the generated salt's hex value instead of Base64.");
+ private static final Option NO_SALT_GEN = new Option("ngs", "nogensalt", false, "do NOT generate and use a random salt (valid during password hashing).");
private static final Option SALT_GEN_SIZE = new Option("gss", "gensaltsize", true, "the number of salt bits (not bytes!) to generate. Defaults to 128.");
- private static final Option SHIRO = new Option("shiro", "shiro", false, "display output in the Shiro password file format (.ini [users] config).");
private static final String HEX_PREFIX = "0x";
private static final String DEFAULT_ALGORITHM_NAME = "MD5";
+ private static final String DEFAULT_PASSWORD_ALGORITHM_NAME = "SHA-256";
private static final int DEFAULT_GENERATED_SALT_SIZE = 128;
private static final int DEFAULT_NUM_ITERATIONS = 1;
+ private static final int DEFAULT_PASSWORD_NUM_ITERATIONS = 350000;
private static final String SALT_MUTEX_MSG = createMutexMessage(SALT, SALT_BYTES);
+ private static final HashFormatFactory HASH_FORMAT_FACTORY = new DefaultHashFormatFactory();
+
static {
ALGORITHM.setArgName("name");
SALT_GEN_SIZE.setArgName("numBits");
@@ -81,26 +84,23 @@ public final class Hasher {
CommandLineParser parser = new PosixParser();
Options options = new Options();
- options.addOption(HELP).addOption(DEBUG).addOption(ALGORITHM).addOption(HEX).addOption(ITERATIONS);
+ options.addOption(HELP).addOption(DEBUG).addOption(ALGORITHM).addOption(ITERATIONS);
options.addOption(RESOURCE).addOption(PASSWORD).addOption(PASSWORD_NC);
- options.addOption(SALT).addOption(SALT_BYTES).addOption(SALT_GEN).addOption(SALT_GEN_SIZE).addOption(SALT_GEN_HEX);
- options.addOption(NO_FORMAT).addOption(SHIRO);
+ options.addOption(SALT).addOption(SALT_BYTES).addOption(SALT_GEN).addOption(SALT_GEN_SIZE).addOption(NO_SALT_GEN);
+ options.addOption(FORMAT);
boolean debug = false;
- String algorithm = DEFAULT_ALGORITHM_NAME;
- int iterations = DEFAULT_NUM_ITERATIONS;
- boolean base64 = true;
+ String algorithm = null; //user unspecified
+ int iterations = 0; //0 means unspecified by the end-user
boolean resource = false;
boolean password = false;
boolean passwordConfirm = true;
String saltString = null;
String saltBytesString = null;
boolean generateSalt = false;
- boolean generatedSaltBase64 = true;
int generatedSaltSize = DEFAULT_GENERATED_SALT_SIZE;
- boolean shiroFormat = false;
- boolean format = true;
+ String formatString = null;
char[] passwordChars = null;
@@ -119,17 +119,16 @@ public final class Hasher {
if (line.hasOption(ITERATIONS.getOpt())) {
iterations = getRequiredPositiveInt(line, ITERATIONS);
}
- if (line.hasOption(HEX.getOpt())) {
- base64 = false;
- }
if (line.hasOption(PASSWORD.getOpt())) {
password = true;
+ generateSalt = true;
}
if (line.hasOption(RESOURCE.getOpt())) {
resource = true;
}
if (line.hasOption(PASSWORD_NC.getOpt())) {
password = true;
+ generateSalt = true;
passwordConfirm = false;
}
if (line.hasOption(SALT.getOpt())) {
@@ -138,12 +137,11 @@ public final class Hasher {
if (line.hasOption(SALT_BYTES.getOpt())) {
saltBytesString = line.getOptionValue(SALT_BYTES.getOpt());
}
- if (line.hasOption(SALT_GEN.getOpt())) {
- generateSalt = true;
+ if (line.hasOption(NO_SALT_GEN.getOpt())) {
+ generateSalt = false;
}
- if (line.hasOption(SALT_GEN_HEX.getOpt())) {
+ if (line.hasOption(SALT_GEN.getOpt())) {
generateSalt = true;
- generatedSaltBase64 = false;
}
if (line.hasOption(SALT_GEN_SIZE.getOpt())) {
generateSalt = true;
@@ -152,14 +150,11 @@ public final class Hasher {
throw new IllegalArgumentException("Generated salt size must be a multiple of 8 (e.g. 128, 192, 256, 512, etc).");
}
}
- if (line.hasOption(NO_FORMAT.getOpt())) {
- format = false;
- }
- if (line.hasOption(SHIRO.getOpt())) {
- shiroFormat = true;
+ if (line.hasOption(FORMAT.getOpt())) {
+ formatString = line.getOptionValue(FORMAT.getOpt());
}
- String sourceValue = null;
+ String sourceValue;
Object source;
@@ -186,19 +181,45 @@ public final class Hasher {
}
}
+ if (algorithm == null) {
+ if (password) {
+ algorithm = DEFAULT_PASSWORD_ALGORITHM_NAME;
+ } else {
+ algorithm = DEFAULT_ALGORITHM_NAME;
+ }
+ }
+
+ if (iterations < DEFAULT_NUM_ITERATIONS) {
+ //Iterations were not specified. Default to 350,000 when password hashing, and 1 for everything else:
+ if (password) {
+ iterations = DEFAULT_PASSWORD_NUM_ITERATIONS;
+ } else {
+ iterations = DEFAULT_NUM_ITERATIONS;
+ }
+ }
+
ByteSource salt = getSalt(saltString, saltBytesString, generateSalt, generatedSaltSize);
SimpleHash hash = new SimpleHash(algorithm, source, salt, iterations);
- StringBuilder output;
- if (shiroFormat) {
- output = formatForShiroIni(hash, base64, salt, generatedSaltBase64, generateSalt);
- } else if (format) {
- output = format(hash, base64, salt, generatedSaltBase64, generateSalt, algorithm, sourceValue);
- } else {
- output = formatMinimal(hash, base64, salt, generatedSaltBase64, generateSalt);
+ if (formatString == null) {
+ //Output format was not specified. Default to 'shiro1' when password hashing, and 'hex' for
+ //everything else:
+ if (password) {
+ formatString = Shiro1CryptFormat.class.getName();
+ } else {
+ formatString = HexFormat.class.getName();
+ }
+ }
+
+ HashFormat format = HASH_FORMAT_FACTORY.getInstance(formatString);
+
+ if (format == null) {
+ throw new IllegalArgumentException("Unrecognized hash format '" + formatString + "'.");
}
+ String output = format.format(hash);
+
System.out.println(output);
} catch (IllegalArgumentException iae) {
@@ -238,72 +259,6 @@ public final class Hasher {
System.exit(-1);
}
- private static StringBuilder format(ByteSource hash, boolean hashBase64, ByteSource salt, boolean saltBase64, boolean showSalt, String alg, String value) {
- StringBuilder sb = new StringBuilder();
-
- sb.append(alg).append("(").append(value).append(")");
-
- if (hashBase64) {
- sb.append(" base64 = ").append(hash.toBase64());
- } else {
- sb.append(" hex = ").append(hash.toHex());
- }
-
- if (showSalt && salt != null) {
- sb.append("\nGenerated salt");
- if (saltBase64) {
- sb.append(" base64 = ").append(salt.toBase64());
- } else {
- sb.append(" hex = ").append(salt.toHex());
- }
- }
-
- return sb;
- }
-
- private static StringBuilder formatForShiroIni(ByteSource hash, boolean hashBase64, ByteSource salt, boolean saltBase64, boolean showSalt) {
- StringBuilder sb = new StringBuilder();
-
- if (hashBase64) {
- sb.append(hash.toBase64());
- } else {
- //hex:
- sb.append(HEX_PREFIX).append(hash.toHex());
- }
-
- if (showSalt && salt != null) {
- sb.append(" ");
- if (saltBase64) {
- sb.append(salt.toBase64());
- } else {
- //hex:
- sb.append(HEX_PREFIX).append(salt.toHex());
- }
- }
- return sb;
- }
-
- private static StringBuilder formatMinimal(ByteSource hash, boolean hashBase64, ByteSource salt, boolean saltBase64, boolean showSalt) {
- StringBuilder sb = new StringBuilder();
-
- if (hashBase64) {
- sb.append(hash.toBase64());
- } else {
- sb.append(hash.toHex());
- }
-
- if (showSalt && salt != null) {
- sb.append(" ");
- if (saltBase64) {
- sb.append(salt.toBase64());
- } else {
- sb.append(salt.toHex());
- }
- }
-
- return sb;
- }
-
private static int getRequiredPositiveInt(CommandLine line, Option option) {
String iterVal = line.getOptionValue(option.getOpt());
try {
@@ -387,7 +342,6 @@ public final class Hasher {
"---------------------------------\n" +
"Specifying a salt:" +
"\n\n" +
-
"You may specify a salt using the -s/--salt option followed by the salt\n" +
"value. If the salt value is a base64 or hex string representing a\n" +
"byte array, you must specify the -sb/--saltbytes option to indicate this,\n" +
@@ -401,9 +355,9 @@ public final class Hasher {
"\n\n" +
"Use the -sg/--saltgenerated option if you don't want to specify a salt,\n" +
"but want a strong random salt to be generated and used during hashing.\n" +
- "The generated salt size defaults to 128 bytes. You may specify\n" +
+ "The generated salt size defaults to 128 bits. You may specify\n" +
"a different size by using the -sgs/--saltgeneratedsize option followed by\n" +
- "a positive integer." +
+ "a positive integer (size is in bits, not bytes)." +
"\n\n" +
"Because a salt must be specified if computing the\n" +
"hash later, generated salts will be printed, defaulting to base64\n" +
@@ -424,7 +378,18 @@ public final class Hasher {
"<command> -r ~/documents/myfile.pdf\n" +
"<command> -r /usr/local/logs/absolutePathFile.log\n" +
"<command> -r url:http://foo.com/page.html\n" +
- "<command> -r classpath:/WEB-INF/lib/something.jar";
+ "<command> -r classpath:/WEB-INF/lib/something.jar" +
+ "\n\n" +
+ "Output Format:\n" +
+ "---------------------------------\n" +
+ "Specify the -f/--format option followed by either 1) the format ID (as defined\n" +
+ "by the " + DefaultHashFormatFactory.class.getName() + "\n" +
+ "JavaDoc) or 2) the fully qualified " + HashFormat.class.getName() + "\n" +
+ "implementation class name to instantiate and use for formatting.\n\n" +
+ "The default output format is 'shiro1' which is a Modular Crypt Format (MCF)\n" +
+ "that shows all relevant information as a dollar-sign ($) delimited string.\n" +
+ "This format is ideal for use in Shiro's text-based user configuration (e.g.\n" +
+ "shiro.ini or a properties file).";
printException(e, debug);
Modified: shiro/trunk/web/src/main/java/org/apache/shiro/web/env/DefaultWebEnvironment.java
URL: http://svn.apache.org/viewvc/shiro/trunk/web/src/main/java/org/apache/shiro/web/env/DefaultWebEnvironment.java?rev=1209662&r1=1209661&r2=1209662&view=diff
==============================================================================
--- shiro/trunk/web/src/main/java/org/apache/shiro/web/env/DefaultWebEnvironment.java (original)
+++ shiro/trunk/web/src/main/java/org/apache/shiro/web/env/DefaultWebEnvironment.java Fri Dec 2 19:52:37 2011
@@ -42,11 +42,11 @@ public class DefaultWebEnvironment exten
}
public FilterChainResolver getFilterChainResolver() {
- return (FilterChainResolver)this.objects.get(DEFAULT_FILTER_CHAIN_RESOLVER_NAME);
+ return getObject(DEFAULT_FILTER_CHAIN_RESOLVER_NAME, FilterChainResolver.class);
}
public void setFilterChainResolver(FilterChainResolver filterChainResolver) {
- this.objects.put(DEFAULT_FILTER_CHAIN_RESOLVER_NAME, filterChainResolver);
+ setObject(DEFAULT_FILTER_CHAIN_RESOLVER_NAME, filterChainResolver);
}
@Override
Modified: shiro/trunk/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java
URL: http://svn.apache.org/viewvc/shiro/trunk/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java?rev=1209662&r1=1209661&r2=1209662&view=diff
==============================================================================
--- shiro/trunk/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java (original)
+++ shiro/trunk/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java Fri Dec 2 19:52:37 2011
@@ -35,13 +35,10 @@ import javax.servlet.http.HttpServletReq
import javax.servlet.http.HttpServletResponse;
import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
/**
- * TODO - Class JavaDoc
+ * Unit tests for the {@link CookieRememberMeManager} implementation.
*
* @since 1.0
*/
@@ -125,13 +122,13 @@ public class CookieRememberMeManagerTest
//The following base64 string was determined from the log output of the above 'onSuccessfulLogin' test.
//This will have to change any time the PrincipalCollection implementation changes:
- final String userPCAesBase64 = "qk7spFqO1zoNLgq3qArE7bc8+J+Zvm1jz8lDSUmRiRlDQQx7jxG4+" +
- "QImiRpR7zO0d9oHH+7C3VeN9OvGMdjxtpbInMsLcGz4Q0u3M1fmyErn5Mr61chmNzQ8cLegpIKE3M+xMY" +
- "5JB1PRw7aEJdRxtHh80kiXZ5jeALvDP3hmFM7OF2CDKLIIa83XuBQvyrKGI9GhsxGTLkmNFknbfRsmN7v" +
- "NIDorceeaMkAetYf6GxDOw1ZK7yEbsydIHnqVWNHLen6DHC8pLkqMNOoGwXLeBroD6mRpoFf76J0VKBcd" +
- "C54Mg73S2R7wx9ZzSNJJrCi1KAilmThzm3Rm97EidUnYlWI0TM+zvMzNsLynIK4PoIG6HYQQfEI35qVRI" +
- "bCdbTlTnjfM/fPf7RWO8s4Z7KzszSQMJE9LgBudcyzrld5ZrWb11cianskNZMI8kzOITezjjqvWn5U4jg" +
- "Mb9a6qcpaNJcgaxV6NZRmof8cnet54wwE=";
+ final String userPCAesBase64 = "WlD5MLzzZznN3dQ1lPJO/eScSuY245k29aECNmjUs31o7Yu478hWhaM5Sj" +
+ "jmoe900/72JNu3hcJaPG6Q17Vuz4F8x0kBjbFnPVx4PqzsZYT6yreeS2jwO6OwfI+efqXOKyB2a5KPtnr" +
+ "7jt5kZsyH38XJISb81cf6xqTGUru8zC+kNqJFz7E5RpO0kraBofS5jhMm45gDVjDRkjgPJAzocVWMtrza" +
+ "zy67P8eb+kMSBCqGI251JTNAGboVgQ28KjfaAJ/6LXRJUj7kB7CGia7mgRk+hxzEJGDs81at5VOPqODJr" +
+ "xb8tcIdemFUFIkiYVP9bGs4dP3ECtmw7aNrCzv+84sx3vRFUrd5DbDYpEuE12hF2Y9owDK9sxStbXoF0y" +
+ "A32dhfGDIqS+agsass0sWn8WX2TM9i8SxrUjiFbxqyIG49HbqGrZp5QLM9IuIwO+TzGfF1FzumQGdwmWT" +
+ "xkVapw5UESl34YvA615cb+82ue1I=";
Cookie[] cookies = new Cookie[]{
new Cookie(CookieRememberMeManager.DEFAULT_REMEMBER_ME_COOKIE_NAME, userPCAesBase64)