Author: lhazlewood
Date: Mon Mar 28 02:55:23 2011
New Revision: 1086106
URL: http://svn.apache.org/viewvc?rev=1086106&view=rev
Log:
SHIRO-279: Implemented command-line/console hashing program. It will hash
strings, resources (files, urls, classpath entries), and passwords. It allows
specification of the hash algorithm and number of hash iterations, defaulting
to MD5 and 1 respectively. Salting is not performed at the moment.
Added:
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/UnknownAlgorithmException.java
shiro/trunk/tools/ (with props)
shiro/trunk/tools/hasher/ (with props)
shiro/trunk/tools/hasher/pom.xml
shiro/trunk/tools/hasher/src/
shiro/trunk/tools/hasher/src/main/
shiro/trunk/tools/hasher/src/main/java/
shiro/trunk/tools/hasher/src/main/java/org/
shiro/trunk/tools/hasher/src/main/java/org/apache/
shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/
shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/
shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/
shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/Hasher.java
shiro/trunk/tools/pom.xml
Modified:
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java
shiro/trunk/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java
shiro/trunk/pom.xml
Added:
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/UnknownAlgorithmException.java
URL:
http://svn.apache.org/viewvc/shiro/trunk/core/src/main/java/org/apache/shiro/crypto/UnknownAlgorithmException.java?rev=1086106&view=auto
==============================================================================
---
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/UnknownAlgorithmException.java
(added)
+++
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/UnknownAlgorithmException.java
Mon Mar 28 02:55:23 2011
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.crypto;
+
+/**
+ * Exception thrown when attempting to lookup or use a cryptographic algorithm
that does not exist in the current
+ * JVM environment.
+ *
+ * @since 1.2
+ */
+public class UnknownAlgorithmException extends CryptoException {
+
+ public UnknownAlgorithmException(String message) {
+ super(message);
+ }
+
+ public UnknownAlgorithmException(Throwable cause) {
+ super(cause);
+ }
+
+ public UnknownAlgorithmException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Modified:
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java
URL:
http://svn.apache.org/viewvc/shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java?rev=1086106&r1=1086105&r2=1086106&view=diff
==============================================================================
---
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java
(original)
+++
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java
Mon Mar 28 02:55:23 2011
@@ -22,6 +22,7 @@ import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.CodecException;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.codec.Hex;
+import org.apache.shiro.crypto.UnknownAlgorithmException;
import java.io.Serializable;
import java.security.MessageDigest;
@@ -166,13 +167,14 @@ public abstract class AbstractHash exten
*
* @param algorithmName the algorithm to use for the hash, provided by
subclasses.
* @return the MessageDigest object for the specified {@code algorithm}.
+ * @throws UnknownAlgorithmException if the specified algorithm name is
not available.
*/
- protected MessageDigest getDigest(String algorithmName) {
+ protected MessageDigest getDigest(String algorithmName) throws
UnknownAlgorithmException {
try {
return MessageDigest.getInstance(algorithmName);
} catch (NoSuchAlgorithmException e) {
String msg = "No native '" + algorithmName + "' MessageDigest
instance available on the current JVM.";
- throw new IllegalStateException(msg, e);
+ throw new UnknownAlgorithmException(msg, e);
}
}
@@ -204,8 +206,9 @@ public abstract class AbstractHash exten
* @param salt the salt to use for the initial hash
* @param hashIterations the number of times the the {@code bytes} will be
hashed (for attack resiliency).
* @return the hashed bytes.
+ * @throws UnknownAlgorithmException if the {@link #getAlgorithmName()
algorithmName} is not available.
*/
- protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) {
+ protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations)
throws UnknownAlgorithmException {
MessageDigest digest = getDigest(getAlgorithmName());
if (salt != null) {
digest.reset();
Modified:
shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java
URL:
http://svn.apache.org/viewvc/shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java?rev=1086106&r1=1086105&r2=1086106&view=diff
==============================================================================
--- shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java
(original)
+++ shiro/trunk/core/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java
Mon Mar 28 02:55:23 2011
@@ -21,6 +21,7 @@ package org.apache.shiro.crypto.hash;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.CodecException;
import org.apache.shiro.codec.Hex;
+import org.apache.shiro.crypto.UnknownAlgorithmException;
import org.apache.shiro.util.StringUtils;
import java.security.MessageDigest;
@@ -67,9 +68,13 @@ public class SimpleHash extends Abstract
* constructor is useful in scenarios when you have a byte array that you
know is already hashed and
* just want to set the bytes in their raw form directly on an instance.
After using this constructor,
* you can then immediately call {@link #setBytes setBytes} to have a
fully-initialized instance.
+ * <p/>
+ * <b>N.B.</b>The algorithm identified by the {@code algorithmName}
parameter must be available on the JVM. If it
+ * is not, a {@link UnknownAlgorithmException} will be thrown when the
hash is performed (not at instantiation).
*
* @param algorithmName the {@link java.security.MessageDigest
MessageDigest} algorithm name to use when
* performing the hash.
+ * @see UnknownAlgorithmException
*/
public SimpleHash(String algorithmName) {
this.algorithmName = algorithmName;
@@ -90,9 +95,10 @@ public class SimpleHash extends Abstract
* performing the hash.
* @param source the object to be hashed.
* @throws org.apache.shiro.codec.CodecException
- * if the specified {@code source} cannot be converted into a
byte array (byte[]).
+ * if the specified {@code source}
cannot be converted into a byte array (byte[]).
+ * @throws UnknownAlgorithmException if the {@code algorithmName} is not
available.
*/
- public SimpleHash(String algorithmName, Object source) throws
CodecException {
+ public SimpleHash(String algorithmName, Object source) throws
CodecException, UnknownAlgorithmException {
this(algorithmName, source, null, 1);
}
@@ -111,9 +117,10 @@ public class SimpleHash extends Abstract
* performing the hash.
* @param source the source object to be hashed.
* @param salt the salt to use for the hash
- * @throws CodecException if either constructor argument cannot be
converted into a byte array.
+ * @throws CodecException if either constructor argument cannot
be converted into a byte array.
+ * @throws UnknownAlgorithmException if the {@code algorithmName} is not
available.
*/
- public SimpleHash(String algorithmName, Object source, Object salt) throws
CodecException {
+ public SimpleHash(String algorithmName, Object source, Object salt) throws
CodecException, UnknownAlgorithmException {
this(algorithmName, source, salt, 1);
}
@@ -137,9 +144,11 @@ public class SimpleHash extends Abstract
* @param source the source object to be hashed.
* @param salt the salt to use for the hash
* @param hashIterations the number of times the {@code source} argument
hashed for attack resiliency.
- * @throws CodecException if either Object constructor argument cannot be
converted into a byte array.
+ * @throws CodecException if either Object constructor argument
cannot be converted into a byte array.
+ * @throws UnknownAlgorithmException if the {@code algorithmName} is not
available.
*/
- public SimpleHash(String algorithmName, Object source, Object salt, int
hashIterations) throws CodecException {
+ public SimpleHash(String algorithmName, Object source, Object salt, int
hashIterations)
+ throws CodecException, UnknownAlgorithmException {
if (!StringUtils.hasText(algorithmName)) {
throw new NullPointerException("algorithmName argument cannot be
null or empty.");
}
@@ -147,7 +156,7 @@ public class SimpleHash extends Abstract
hash(source, salt, hashIterations);
}
- private void hash(Object source, Object salt, int hashIterations) throws
CodecException {
+ private void hash(Object source, Object salt, int hashIterations) throws
CodecException, UnknownAlgorithmException {
byte[] sourceBytes = toBytes(source);
byte[] saltBytes = null;
if (salt != null) {
@@ -189,13 +198,14 @@ public class SimpleHash extends Abstract
*
* @param algorithmName the algorithm to use for the hash, provided by
subclasses.
* @return the MessageDigest object for the specified {@code algorithm}.
+ * @throws UnknownAlgorithmException if the specified algorithm name is
not available.
*/
- protected MessageDigest getDigest(String algorithmName) {
+ protected MessageDigest getDigest(String algorithmName) throws
UnknownAlgorithmException {
try {
return MessageDigest.getInstance(algorithmName);
} catch (NoSuchAlgorithmException e) {
String msg = "No native '" + algorithmName + "' MessageDigest
instance available on the current JVM.";
- throw new IllegalStateException(msg, e);
+ throw new UnknownAlgorithmException(msg, e);
}
}
@@ -204,8 +214,9 @@ public class SimpleHash extends Abstract
*
* @param bytes the bytes to hash.
* @return the hashed bytes.
+ * @throws UnknownAlgorithmException if the configured {@link
#getAlgorithmName() algorithmName} is not available.
*/
- protected byte[] hash(byte[] bytes) {
+ protected byte[] hash(byte[] bytes) throws UnknownAlgorithmException {
return hash(bytes, null, 1);
}
@@ -215,8 +226,9 @@ public class SimpleHash extends Abstract
* @param bytes the bytes to hash
* @param salt the salt to use for the initial hash
* @return the hashed bytes
+ * @throws UnknownAlgorithmException if the configured {@link
#getAlgorithmName() algorithmName} is not available.
*/
- protected byte[] hash(byte[] bytes, byte[] salt) {
+ protected byte[] hash(byte[] bytes, byte[] salt) throws
UnknownAlgorithmException {
return hash(bytes, salt, 1);
}
@@ -227,8 +239,9 @@ public class SimpleHash extends Abstract
* @param salt the salt to use for the initial hash
* @param hashIterations the number of times the the {@code bytes} will be
hashed (for attack resiliency).
* @return the hashed bytes.
+ * @throws UnknownAlgorithmException if the {@link #getAlgorithmName()
algorithmName} is not available.
*/
- protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) {
+ protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations)
throws UnknownAlgorithmException {
MessageDigest digest = getDigest(getAlgorithmName());
if (salt != null) {
digest.reset();
Modified:
shiro/trunk/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java
URL:
http://svn.apache.org/viewvc/shiro/trunk/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java?rev=1086106&r1=1086105&r2=1086106&view=diff
==============================================================================
--- shiro/trunk/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java
(original)
+++ shiro/trunk/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java
Mon Mar 28 02:55:23 2011
@@ -144,4 +144,20 @@ public abstract class JavaEnvironment {
public static boolean isAtLeastVersion15() {
return getMajorVersion() >= JAVA_15;
}
+
+ /**
+ * Convenience method to determine if the current JVM is at least
+ * Java 1.6 (Java 6).
+ *
+ * @return <code>true</code> if the current JVM is at least Java 1.6
+ * @see #getMajorVersion()
+ * @see #JAVA_15
+ * @see #JAVA_16
+ * @see #JAVA_17
+ *
+ * @since 1.2
+ */
+ public static boolean isAtLeastVersion16() {
+ return getMajorVersion() >= JAVA_16;
+ }
}
Modified: shiro/trunk/pom.xml
URL:
http://svn.apache.org/viewvc/shiro/trunk/pom.xml?rev=1086106&r1=1086105&r2=1086106&view=diff
==============================================================================
--- shiro/trunk/pom.xml (original)
+++ shiro/trunk/pom.xml Mon Mar 28 02:55:23 2011
@@ -71,6 +71,7 @@
<!-- Don't change this version without also changing the shiro-aspect
and shiro-features
modules' OSGi metadata: -->
<aspectj.version>1.6.9</aspectj.version>
+ <commons.cli.version>1.2</commons.cli.version>
<crowd.version>1.5.2</crowd.version>
<!-- Don't change this version without also changing the shiro-ehcache
and shiro-features
modules' OSGi metadata: -->
@@ -168,6 +169,7 @@
<module>web</module>
<module>support</module>
<module>samples</module>
+ <module>tools</module>
<module>all</module>
</modules>
@@ -378,6 +380,7 @@
<version>${project.version}</version>
</dependency>
+
<!-- Intra project test dependencies: -->
<dependency>
<groupId>org.apache.shiro</groupId>
@@ -389,6 +392,12 @@
<!-- 3rd party dependencies -->
<dependency>
+ <!-- used for the 'hashpass' command line tool: -->
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>${commons.cli.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
Propchange: shiro/trunk/tools/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Mon Mar 28 02:55:23 2011
@@ -0,0 +1 @@
+*.iml
Propchange: shiro/trunk/tools/hasher/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Mon Mar 28 02:55:23 2011
@@ -0,0 +1 @@
+*.iml
Added: shiro/trunk/tools/hasher/pom.xml
URL:
http://svn.apache.org/viewvc/shiro/trunk/tools/hasher/pom.xml?rev=1086106&view=auto
==============================================================================
--- shiro/trunk/tools/hasher/pom.xml (added)
+++ shiro/trunk/tools/hasher/pom.xml Mon Mar 28 02:55:23 2011
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>org.apache.shiro.tools</groupId>
+ <artifactId>shiro-tools</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>shiro-tools-hasher</artifactId>
+ <name>Apache Shiro :: Tools :: Hasher</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-core</artifactId>
+ <exclusions>
+ <!-- BeanUtils is for ini config - this simple command line
program
+ does not init a shiro environment, so we don't need it:
-->
+ <exclusion>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2.1</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ <!-- use the default artifact name, overwriting the
original. This is only
+ for Command Line use and won't be referenced as a
library: -->
+
<finalName>${project.artifactId}-${project.version}-cli</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <archive>
+ <manifest>
+
<mainClass>org.apache.shiro.tools.hasher.Hasher</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <!-- this is used for inheritance merges: -->
+ <id>make-assembly</id>
+ <!-- bind to the packaging phase: -->
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+
<Bundle-SymbolicName>org.apache.shiro.tools.hasher</Bundle-SymbolicName>
+
<Export-Package>org.apache.shiro.tools.hasher*;version=${project.version}</Export-Package>
+ <Import-Package>
+
org.apache.shiro*;version="${shiro.osgi.importRange}",
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
Added:
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=1086106&view=auto
==============================================================================
---
shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/Hasher.java
(added)
+++
shiro/trunk/tools/hasher/src/main/java/org/apache/shiro/tools/hasher/Hasher.java
Mon Mar 28 02:55:23 2011
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.tools.hasher;
+
+import org.apache.commons.cli.*;
+import org.apache.shiro.crypto.UnknownAlgorithmException;
+import org.apache.shiro.crypto.hash.SimpleHash;
+import org.apache.shiro.io.ResourceUtils;
+import org.apache.shiro.util.JavaEnvironment;
+import org.apache.shiro.util.StringUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Commandline line utility to hash data such as strings, passwords, resources
(files, urls, etc).
+ * <p/>
+ * Usage:
+ * <pre>
+ * java -jar shiro-tools-hasher<em>-version</em>.jar
+ * </pre>
+ * This will print out all supported options with documentation.
+ *
+ * @since 1.2
+ */
+public final class Hasher {
+
+
+ private static final String DEFAULT_ALGORITHM_NAME = "MD5";
+ private static final int DEFAULT_NUM_ITERATIONS = 1;
+
+ private static final String ALG_OPT = "a";
+ private static final String ALG_OPT_LONG = "algorithm";
+ private static final String DEBUG_OPT = "d";
+ private static final String DEBUG_OPT_LONG = "debug"; //show stack traces
if there are any.
+ private static final String ITER_OPT = "i";
+ private static final String ITER_OPT_LONG = "iterations";
+ private static final String HEX_OPT = "h";
+ private static final String HEX_OPT_LONG = "hex";
+ private static final String HELP_OPT = "help";
+ private static final String HELP_OPT_LONG = "help";
+ private static final String PASSWORD_OPT = "p";
+ private static final String PASSWORD_OPT_LONG = "password";
+ private static final String PASSWORD_OPT_NOCONFIRM = "pnc";
+ private static final String PASSWORD_OPT_NOCONFIRM_LONG = "pnoconfirm";
+ private static final String RESOURCE_OPT = "r";
+ private static final String RESOURCE_OPT_LONG = "resource";
+
+
+ public static void main(String[] args) {
+
+ CommandLineParser parser = new PosixParser();
+
+ Options options = new Options();
+ options.addOption(ALG_OPT, ALG_OPT_LONG, true, "hash algorithm name.
Defaults to MD5.");
+ options.addOption(ITER_OPT, ITER_OPT_LONG, true, "number of hash
iterations. Defaults to 1.");
+ options.addOption(HEX_OPT, HEX_OPT_LONG, false, "print hex value.
Defaults to Base64.");
+ options.addOption(HELP_OPT, HELP_OPT_LONG, false, "print this help
message.");
+ options.addOption(DEBUG_OPT, DEBUG_OPT_LONG, false, "show additional
error (stack trace) information.");
+ options.addOption(PASSWORD_OPT, PASSWORD_OPT_LONG, false, "hash a
password (do not echo).");
+ options.addOption(RESOURCE_OPT, RESOURCE_OPT_LONG, false, "read and
hash the resource located at <value>. See below for more information.");
+ options.addOption(PASSWORD_OPT_NOCONFIRM, PASSWORD_OPT_NOCONFIRM_LONG,
false, "disable confirmation prompt for password hashing.");
+
+ boolean debug = false;
+ String algorithm = DEFAULT_ALGORITHM_NAME;
+ int iterations = DEFAULT_NUM_ITERATIONS;
+ boolean base64 = true;
+ boolean resource = false;
+ boolean password = false;
+ boolean passwordConfirm = true;
+
+ char[] passwordChars = null;
+
+ try {
+ CommandLine line = parser.parse(options, args);
+
+ if (line.hasOption(HELP_OPT)) {
+ printHelpAndExit(options, null, debug, 0);
+ }
+ if (line.hasOption(DEBUG_OPT)) {
+ debug = true;
+ }
+ if (line.hasOption(ALG_OPT)) {
+ algorithm = line.getOptionValue(ALG_OPT);
+ }
+ if (line.hasOption(ITER_OPT)) {
+ iterations = getRequiredPositiveInt(line, ITER_OPT,
ITER_OPT_LONG);
+ }
+ if (line.hasOption(HEX_OPT)) {
+ base64 = false;
+ }
+ if (line.hasOption(PASSWORD_OPT)) {
+ password = true;
+ }
+ if (line.hasOption(RESOURCE_OPT)) {
+ resource = true;
+ }
+ if (line.hasOption(PASSWORD_OPT_NOCONFIRM)) {
+ passwordConfirm = false;
+ }
+
+ Object source;
+
+ if (password) {
+ passwordChars = readPassword(passwordConfirm);
+ source = passwordChars;
+ } else {
+ String[] remainingArgs = line.getArgs();
+ if (remainingArgs == null || remainingArgs.length != 1) {
+ printHelpAndExit(options, null, debug, -1);
+ }
+
+ assert remainingArgs != null;
+ String value = toString(remainingArgs);
+
+ if (resource) {
+ if (!ResourceUtils.hasResourcePrefix(value)) {
+ source = toFile(value);
+ } else {
+ source = ResourceUtils.getInputStreamForPath(value);
+ }
+ } else {
+ source = value;
+ }
+ }
+
+ SimpleHash hash = new SimpleHash(algorithm, source, /* salt not
supported yet*/ null, iterations);
+ if (base64) {
+ System.out.println(hash.toBase64());
+ } else {
+ System.out.println(hash.toHex());
+ }
+ } catch (IllegalArgumentException iae) {
+ exit(iae, debug);
+ } catch (UnknownAlgorithmException uae) {
+ exit(uae, debug);
+ } catch (IOException ioe) {
+ exit(ioe, debug);
+ } catch (Exception e) {
+ printHelpAndExit(options, e, debug, -1);
+ } finally {
+ if (passwordChars != null && passwordChars.length > 0) {
+ for (int i = 0; i < passwordChars.length; i++) {
+ passwordChars[i] = ' ';
+ }
+ }
+ }
+ }
+
+ private static String toString(String[] strings) {
+ int len = strings != null ? strings.length : 0;
+ if (len == 0) {
+ return null;
+ }
+ return StringUtils.toDelimitedString(strings, " ");
+ }
+
+ private static int getRequiredPositiveInt(CommandLine line, String opt,
String optLong) {
+ String iterVal = line.getOptionValue(opt);
+ try {
+ return Integer.parseInt(iterVal);
+ } catch (NumberFormatException e) {
+ String msg = "'" + optLong + "' value must be a positive integer.";
+ throw new IllegalArgumentException(msg, e);
+ }
+ }
+
+ private static File toFile(String path) {
+ String resolved = path;
+ if (path.startsWith("~/") || path.startsWith(("~\\"))) {
+ resolved = path.replaceFirst("\\~",
System.getProperty("user.home"));
+ }
+ return new File(resolved);
+ }
+
+ private static char[] readPassword(boolean confirm) {
+ if (!JavaEnvironment.isAtLeastVersion16()) {
+ String msg = "Password hashing (prompt without echo) uses the
java.io.Console to read passwords " +
+ "safely. This is only available on Java 1.6 platforms and
later.";
+ throw new IllegalArgumentException(msg);
+ }
+ java.io.Console console = System.console();
+ if (console == null) {
+ throw new IllegalStateException("java.io.Console is not available
on the current JVM. Cannot read passwords.");
+ }
+ char[] first = console.readPassword("%s", "Password to hash: ");
+ if (first == null || first.length == 0) {
+ throw new IllegalArgumentException("No password specified.");
+ }
+ if (confirm) {
+ char[] second = console.readPassword("%s", "Password to hash
(confirm): ");
+ if (!Arrays.equals(first, second)) {
+ String msg = "Password entries do not match.";
+ throw new IllegalArgumentException(msg);
+ }
+ }
+ return first;
+ }
+
+ private static void printHelp(Options options, Exception e, boolean debug)
{
+ HelpFormatter help = new HelpFormatter();
+ String command = "java -jar shiro-tools-hasher-<version>.jar [options]
[<value>]";
+ String header = "\nPrint a cryptographic hash (aka message digest) of
the specified <value>.\n--\nOptions:";
+ String footer = "\n" +
+ "<value> is optional only when hashing passwords (see below).
It is\n" +
+ "required all other times.\n\n" +
+ "Password Hashing:\n--\n" +
+ "Specify the -p/--password option and DO NOT enter a <value>.
You will\n" +
+ "be prompted for a password and characters will not echo as
you type.\n\n" +
+ "Files, URLs and classpath resources:\n--\n" +
+ "If using the -r/--resource option, the <value> represents a
resource path.\n" +
+ "By default this is expected to be a file path, but you may
specify\n" +
+ "classpath or URL resources by using the classpath: or url:
prefix\n" +
+ "respectively.\n\n" +
+ "Some examples:\n\n" +
+ "<command> -r fileInCurrentDirectory.txt\n" +
+ "<command> -r ../../relativePathFile.xml\n" +
+ "<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";
+
+ printException(e, debug);
+
+ System.out.println();
+ help.printHelp(command, header, options, null);
+ System.out.println(footer);
+ }
+
+ private static void exit(Exception e, boolean debug) {
+ printException(e, debug);
+ System.exit(-1);
+ }
+
+ private static void printException(Exception e, boolean debug) {
+ if (e != null) {
+ System.out.println();
+ if (debug) {
+ System.out.println("Error: ");
+ e.printStackTrace(System.out);
+ System.out.println(e.getMessage());
+
+ } else {
+ System.out.println("Error: " + e.getMessage());
+ System.out.println();
+ System.out.println("Specify -d or --debug for more
information.");
+ }
+ }
+ }
+
+ private static void printHelpAndExit(Options options, Exception e, boolean
debug, int exitCode) {
+ printHelp(options, e, debug);
+ System.exit(exitCode);
+ }
+}
Added: shiro/trunk/tools/pom.xml
URL:
http://svn.apache.org/viewvc/shiro/trunk/tools/pom.xml?rev=1086106&view=auto
==============================================================================
--- shiro/trunk/tools/pom.xml (added)
+++ shiro/trunk/tools/pom.xml Mon Mar 28 02:55:23 2011
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-root</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.shiro.tools</groupId>
+ <artifactId>shiro-tools</artifactId>
+ <name>Apache Shiro :: Tools</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>hasher</module>
+ </modules>
+
+</project>
+