Seam SVN: r10422 - in trunk/src: main/org/jboss/seam/security/crypto and 4 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-04-15 06:12:14 -0400 (Wed, 15 Apr 2009)
New Revision: 10422
Modified:
trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java
trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java
trunk/src/main/org/jboss/seam/security/digest/DigestAuthenticator.java
trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
trunk/src/main/org/jboss/seam/webservice/WSSecurityInterceptor.java
trunk/src/test/unit/org/jboss/seam/test/unit/PasswordHashTest.java
Log:
imports, warnings
Modified: trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java 2009-04-15 07:12:00 UTC (rev 10421)
+++ trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java 2009-04-15 10:12:14 UTC (rev 10422)
@@ -33,7 +33,7 @@
/**
* You may encounter a JVM bug where the field initializer is not evaluated for a transient field after deserialization.
- * @see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6252102
+ * @see "http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6252102"
*/
private transient volatile Map<Method,Restriction> restrictions = new HashMap<Method,Restriction>();
Modified: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java 2009-04-15 07:12:00 UTC (rev 10421)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java 2009-04-15 10:12:14 UTC (rev 10422)
@@ -1,9 +1,6 @@
package org.jboss.seam.security.crypto;
-import java.io.IOException;
import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
/**
* Copied from Matthias Gartner's PKCS#5 implementation - see
Modified: trunk/src/main/org/jboss/seam/security/digest/DigestAuthenticator.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/digest/DigestAuthenticator.java 2009-04-15 07:12:00 UTC (rev 10421)
+++ trunk/src/main/org/jboss/seam/security/digest/DigestAuthenticator.java 2009-04-15 10:12:14 UTC (rev 10422)
@@ -12,6 +12,7 @@
*/
public abstract class DigestAuthenticator
{
+ @SuppressWarnings("deprecation")
protected boolean validatePassword(String password)
{
Context ctx = Contexts.getSessionContext();
Modified: trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java 2009-04-15 07:12:00 UTC (rev 10421)
+++ trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java 2009-04-15 10:12:14 UTC (rev 10422)
@@ -8,7 +8,6 @@
import java.lang.reflect.Type;
import java.security.GeneralSecurityException;
import java.security.Principal;
-import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
Modified: trunk/src/main/org/jboss/seam/webservice/WSSecurityInterceptor.java
===================================================================
--- trunk/src/main/org/jboss/seam/webservice/WSSecurityInterceptor.java 2009-04-15 07:12:00 UTC (rev 10421)
+++ trunk/src/main/org/jboss/seam/webservice/WSSecurityInterceptor.java 2009-04-15 10:12:14 UTC (rev 10422)
@@ -14,7 +14,7 @@
around=AsynchronousInterceptor.class)
public class WSSecurityInterceptor extends SecurityInterceptor
{
-
+ @Override
public boolean isInterceptorEnabled()
{
return getComponent().isSecure() && getComponent().beanClassHasAnnotation("javax.jws.WebService");
Modified: trunk/src/test/unit/org/jboss/seam/test/unit/PasswordHashTest.java
===================================================================
--- trunk/src/test/unit/org/jboss/seam/test/unit/PasswordHashTest.java 2009-04-15 07:12:00 UTC (rev 10421)
+++ trunk/src/test/unit/org/jboss/seam/test/unit/PasswordHashTest.java 2009-04-15 10:12:14 UTC (rev 10422)
@@ -5,6 +5,7 @@
public class PasswordHashTest
{
+ @SuppressWarnings("deprecation")
@Test
public void testMd5Hash()
{
@@ -13,6 +14,7 @@
assert hash.equals("Xr4ilOzQ4PCOq3aQ0qbuaQ==");
}
+ @SuppressWarnings("deprecation")
@Test
public void testShaHash()
{
15 years, 7 months
Seam SVN: r10421 - in trunk/examples/wiki/src: plugin/org/jboss/seam/wiki/plugin/forum and 1 other directory.
by seam-commits@lists.jboss.org
Author: christian.bauer(a)jboss.com
Date: 2009-04-15 03:12:00 -0400 (Wed, 15 Apr 2009)
New Revision: 10421
Modified:
trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiMySQL5HibernateDialect.java
trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumDAO.java
Log:
Minor bugfixes
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiMySQL5HibernateDialect.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiMySQL5HibernateDialect.java 2009-04-15 06:41:39 UTC (rev 10420)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiMySQL5HibernateDialect.java 2009-04-15 07:12:00 UTC (rev 10421)
@@ -36,6 +36,6 @@
// Create all tables as default UTF8!
@Override
public String getTableTypeString() {
- return " ENGINE=InnoDB DEFAULT CHARSET=utf8";
+ return " ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci";
}
}
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumDAO.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumDAO.java 2009-04-15 06:41:39 UTC (rev 10420)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumDAO.java 2009-04-15 07:12:00 UTC (rev 10421)
@@ -36,17 +36,25 @@
}
public Long findForumPostingsCount(List<WikiDirectory> forumDirectories, User user) {
- return (Long) getSession(true).getNamedQuery("forumTopicsForUserCount")
- .setParameterList("parentDirectories", forumDirectories)
- .setParameter("user", user)
- .setComment("Finding forum topcis count for user: " + user)
- .uniqueResult();
+ if (forumDirectories == null || forumDirectories.size() == 0) {
+ return 0l;
+ } else {
+ return (Long) getSession(true).getNamedQuery("forumTopicsForUserCount")
+ .setParameterList("parentDirectories", forumDirectories)
+ .setParameter("user", user)
+ .setComment("Finding forum topcis count for user: " + user)
+ .uniqueResult();
+ }
}
public List<TopicInfo> findForumPostings(List<WikiDirectory> forumDirectories, User user, int firstResult, int maxResults) {
final Map<Long, TopicInfo> topicInfoMap = new LinkedHashMap();
+ if (forumDirectories == null || forumDirectories.size() == 0) {
+ return Collections.EMPTY_LIST;
+ }
+
getSession(true).getNamedQuery("forumTopicsForUser")
.setParameterList("parentDirectories", forumDirectories)
.setParameter("user", user)
15 years, 7 months
Seam SVN: r10420 - in trunk/examples/seamspace: src/org/jboss/seam/example/seamspace and 1 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-04-15 02:41:39 -0400 (Wed, 15 Apr 2009)
New Revision: 10420
Modified:
trunk/examples/seamspace/resources/import.sql
trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/CommentAction.java
trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java
trunk/examples/seamspace/view/hashgen.xhtml
Log:
use the new password hash stuff
Modified: trunk/examples/seamspace/resources/import.sql
===================================================================
--- trunk/examples/seamspace/resources/import.sql 2009-04-15 06:41:04 UTC (rev 10419)
+++ trunk/examples/seamspace/resources/import.sql 2009-04-15 06:41:39 UTC (rev 10420)
@@ -7,10 +7,10 @@
insert into MemberRole (roleid, name, conditional) values (2, 'admin', false);
insert into MemberRole (roleid, name, conditional) values (3, 'friends', true);
-insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (1, 'demo', 'Lb9y5+2nJZ6M4dI9d1Fjy60G21jn9SCY3mpWu4AodsI=', 'dNrc6UsJxXo=', 1, 1);
-insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (2, 'duke', 'Ci9yZp93B/Ig/ElmuBjbq7ldpLp5Dh0Qh4YTP7iquKY=', 'lyEG5QdmTME=', 1, 2);
-insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (3, 'shadowman', 'vNY1tLpId6KQLeTXEB4yShDAyAlwV4BvfPq11HpBHzM=', 'kKBf7ZH3DDk=', 1, 3);
-insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (4, 'mona', 'Vgt0PPvkzacu4qeLYF3USIpN79blPo5TR2JYm0Ak9xA=', 'BM0mitVT6Gg=', 1, 4);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (1, 'demo', '70D33A98C7E76C7365A7C58F88CA8A89373B6EB5', 'C0FA5E59FC18E1E1', 1, 1);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (2, 'duke', '8D18E5D7DB472FF8AA3E3984F16BFDDA2B265598', '576EF3D383B00897', 1, 2);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (3, 'shadowman', '1D70EA4F262D46525F38DA0C1A130FFF1CA02149', '727D5C9995088913', 1, 3);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (4, 'mona', 'CDF580AB2AFC6F7FBCF5A1F114E383DB0DF9E309', '7D804DD05067750C', 1, 4);
insert into AccountMembership (accountid, memberof) values (1, 2);
insert into AccountMembership (accountid, memberof) values (2, 1);
Modified: trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/CommentAction.java
===================================================================
--- trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/CommentAction.java 2009-04-15 06:41:04 UTC (rev 10419)
+++ trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/CommentAction.java 2009-04-15 06:41:39 UTC (rev 10420)
@@ -10,11 +10,13 @@
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.annotations.security.Insert;
import org.jboss.seam.core.Conversation;
@Scope(CONVERSATION)
@Name("commentAction")
+@Transactional
public class CommentAction
{
@In
Modified: trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java
===================================================================
--- trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java 2009-04-15 06:41:04 UTC (rev 10419)
+++ trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java 2009-04-15 06:41:39 UTC (rev 10420)
@@ -4,9 +4,9 @@
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.security.crypto.BinTools;
import org.jboss.seam.security.management.JpaIdentityStore;
import org.jboss.seam.security.management.PasswordHash;
-import org.jboss.seam.util.Base64;
@Scope(ScopeType.EVENT)
@Name("hashgenerator")
@@ -50,8 +50,29 @@
public void generate()
{
- byte[] salt = PasswordHash.instance().generateRandomSalt();
- passwordSalt = Base64.encodeBytes(salt);
+ byte[] salt;
+
+ if (passwordSalt == null || "".equals(passwordSalt.trim()))
+ {
+ salt = PasswordHash.instance().generateRandomSalt();
+ passwordSalt = BinTools.bin2hex(salt);
+ }
+ else
+ {
+ salt = BinTools.hex2bin(passwordSalt);
+ }
+
passwordHash = identityStore.generatePasswordHash(password, salt);
}
+
+ public String getSql()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("INSERT INTO USER_ACCOUNT (username, password_hash, password_salt) values ('johnsmith', '");
+ sb.append(passwordHash);
+ sb.append("', '");
+ sb.append(passwordSalt);
+ sb.append("');");
+ return sb.toString();
+ }
}
Modified: trunk/examples/seamspace/view/hashgen.xhtml
===================================================================
--- trunk/examples/seamspace/view/hashgen.xhtml 2009-04-15 06:41:04 UTC (rev 10419)
+++ trunk/examples/seamspace/view/hashgen.xhtml 2009-04-15 06:41:39 UTC (rev 10420)
@@ -25,6 +25,13 @@
<h:inputText id="password" value="#{hashgenerator.password}" required="true" styleClass="wide"/>
<div class="validationError"><h:message for="password"/></div>
</div>
+
+ <div class="formRow">
+ <h:outputLabel for="salt">Password salt</h:outputLabel>
+ <h:inputText id="salt" value="#{hashgenerator.passwordSalt}" required="false" styleClass="wide"/>
+ <span>(Leave blank to generate a random salt)</span>
+ <div class="validationError"><h:message for="salt"/></div>
+ </div>
<h:commandButton action="#{hashgenerator.generate}" value="Generate hash"/>
@@ -32,8 +39,9 @@
<h2>Results</h2>
- <div>Generated hash (base 64 encoded): <pre>#{hashgenerator.passwordHash}</pre></div>
- <div>Randomly generated password salt (base 64 encoded): <pre>#{hashgenerator.passwordSalt}</pre></div>
+ <div>Generated hash (hex encoded): <pre>#{hashgenerator.passwordHash}</pre></div>
+
+ <div>Example SQL:<br/><textarea style="width:640px;height:50px">#{hashgenerator.sql}</textarea></div>
</ui:define>
15 years, 7 months
Seam SVN: r10419 - in trunk/src/main/org/jboss/seam/security: crypto and 1 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-04-15 02:41:04 -0400 (Wed, 15 Apr 2009)
New Revision: 10419
Added:
trunk/src/main/org/jboss/seam/security/crypto/
trunk/src/main/org/jboss/seam/security/crypto/BinTools.java
trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java
trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java
trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java
trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java
trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java
trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java
trunk/src/main/org/jboss/seam/security/crypto/PRF.java
Modified:
trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
trunk/src/main/org/jboss/seam/security/management/PasswordHash.java
Log:
hashing algorithms in jdk5 suck, so provide our own default one
Added: trunk/src/main/org/jboss/seam/security/crypto/BinTools.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/BinTools.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/BinTools.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,122 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ *
+ * <p>
+ * Free auxiliary functions. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public class BinTools
+{
+ public static final String hex = "0123456789ABCDEF";
+
+ /**
+ * Simple binary-to-hexadecimal conversion.
+ *
+ * @param b
+ * Input bytes. May be <code>null</code>.
+ * @return Hexadecimal representation of b. Uppercase A-F, two characters per
+ * byte. Empty string on <code>null</code> input.
+ */
+ public static String bin2hex(final byte[] b)
+ {
+ if (b == null)
+ {
+ return "";
+ }
+ StringBuffer sb = new StringBuffer(2 * b.length);
+ for (int i = 0; i < b.length; i++)
+ {
+ int v = (256 + b[i]) % 256;
+ sb.append(hex.charAt((v / 16) & 15));
+ sb.append(hex.charAt((v % 16) & 15));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convert hex string to array of bytes.
+ *
+ * @param s
+ * String containing hexadecimal digits. May be <code>null</code>.
+ * On odd length leading zero will be assumed.
+ * @return Array on bytes, non-<code>null</code>.
+ * @throws IllegalArgumentException
+ * when string contains non-hex character
+ */
+ public static byte[] hex2bin(final String s)
+ {
+ String m = s;
+ if (s == null)
+ {
+ // Allow empty input string.
+ m = "";
+ }
+ else if (s.length() % 2 != 0)
+ {
+ // Assume leading zero for odd string length
+ m = "0" + s;
+ }
+ byte r[] = new byte[m.length() / 2];
+ for (int i = 0, n = 0; i < m.length(); n++)
+ {
+ char h = m.charAt(i++);
+ char l = m.charAt(i++);
+ r[n] = (byte) (hex2bin(h) * 16 + hex2bin(l));
+ }
+ return r;
+ }
+
+ /**
+ * Convert hex digit to numerical value.
+ *
+ * @param c
+ * 0-9, a-f, A-F allowd.
+ * @return 0-15
+ * @throws IllegalArgumentException
+ * on non-hex character
+ */
+ public static int hex2bin(char c)
+ {
+ if (c >= '0' && c <= '9')
+ {
+ return (c - '0');
+ }
+ if (c >= 'A' && c <= 'F')
+ {
+ return (c - 'A' + 10);
+ }
+ if (c >= 'a' && c <= 'f')
+ {
+ return (c - 'a' + 10);
+ }
+ throw new IllegalArgumentException("Input string may only contain hex digits, but found '" + c + "'");
+ }
+}
\ No newline at end of file
Added: trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,114 @@
+package org.jboss.seam.security.crypto;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ *
+ * Default PRF implementation based on standard javax.crypt.Mac mechanisms.
+ *
+ * <hr />
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public class MacBasedPRF implements PRF
+{
+ protected Mac mac;
+
+ protected int hLen;
+
+ protected String macAlgorithm;
+
+ /**
+ * Create Mac-based Pseudo Random Function.
+ *
+ * @param macAlgorithm
+ * Mac algorithm to use, i.e. HMacSHA1 or HMacMD5.
+ */
+ public MacBasedPRF(String macAlgorithm)
+ {
+ this.macAlgorithm = macAlgorithm;
+ try
+ {
+ mac = Mac.getInstance(macAlgorithm);
+ hLen = mac.getMacLength();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public MacBasedPRF(String macAlgorithm, String provider)
+ {
+ this.macAlgorithm = macAlgorithm;
+ try
+ {
+ mac = Mac.getInstance(macAlgorithm, provider);
+ hLen = mac.getMacLength();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public byte[] doFinal(byte[] M)
+ {
+ byte[] r = mac.doFinal(M);
+ return r;
+ }
+
+ public int getHLen()
+ {
+ return hLen;
+ }
+
+ public void init(byte[] P)
+ {
+ try
+ {
+ mac.init(new SecretKeySpec(P, macAlgorithm));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,102 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html.
+ *
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public interface PBKDF2
+{
+ /**
+ * Convert String-based input to internal byte array, then invoke PBKDF2.
+ * Desired key length defaults to Pseudo Random Function block size.
+ *
+ * @param inputPassword
+ * Candidate password to compute the derived key for.
+ * @return internal byte array
+ */
+ public abstract byte[] deriveKey(String inputPassword);
+
+ /**
+ * Convert String-based input to internal byte array, then invoke PBKDF2.
+ *
+ * @param inputPassword
+ * Candidate password to compute the derived key for.
+ * @param dkLen
+ * Specify desired key length
+ * @return internal byte array
+ */
+ public abstract byte[] deriveKey(String inputPassword, int dkLen);
+
+ /**
+ * Convert String-based input to internal byte arrays, then invoke PBKDF2 and
+ * verify result against the reference data that is supplied in the
+ * PBKDF2Parameters.
+ *
+ * @param inputPassword
+ * Candidate password to compute the derived key for.
+ * @return <code>true</code> password match; <code>false</code> incorrect
+ * password
+ */
+ public abstract boolean verifyKey(String inputPassword);
+
+ /**
+ * Allow reading of configured parameters.
+ *
+ * @return Currently set parameters.
+ */
+ public abstract PBKDF2Parameters getParameters();
+
+ /**
+ * Allow setting of configured parameters.
+ *
+ * @param parameters
+ */
+ public abstract void setParameters(PBKDF2Parameters parameters);
+
+ /**
+ * Get currently set Pseudo Random Function.
+ *
+ * @return Currently set Pseudo Random Function
+ */
+ public abstract PRF getPseudoRandomFunction();
+
+ /**
+ * Set the Pseudo Random Function to use. Note that deriveKeys/getPRF does
+ * init this object using the supplied candidate password. If this is
+ * undesired, one has to override getPRF.
+ *
+ * @param prf
+ * Pseudo Random Function to set.
+ */
+ public abstract void setPseudoRandomFunction(PRF prf);
+}
\ No newline at end of file
Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,340 @@
+package org.jboss.seam.security.crypto;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ *
+ * <p>
+ * Request for Comments: 2898 PKCS #5: Password-Based Cryptography Specification
+ * <p>
+ * Version 2.0
+ *
+ * <p>
+ * PBKDF2 (P, S, c, dkLen)
+ *
+ * <p>
+ * Options:
+ * <ul>
+ * <li>PRF underlying pseudorandom function (hLen denotes the length in octets
+ * of the pseudorandom function output). PRF is pluggable.</li>
+ * </ul>
+ *
+ * <p>
+ * Input:
+ * <ul>
+ * <li>P password, an octet string</li>
+ * <li>S salt, an octet string</li>
+ * <li>c iteration count, a positive integer</li>
+ * <li>dkLen intended length in octets of the derived key, a positive integer,
+ * at most (2^32 - 1) * hLen</li>
+ * </ul>
+ *
+ * <p>
+ * Output:
+ * <ul>
+ * <li>DK derived key, a dkLen-octet string</li>
+ * </ul>
+ *
+ * <hr />
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898</a>
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public class PBKDF2Engine implements PBKDF2
+{
+ protected PBKDF2Parameters parameters;
+
+ protected PRF prf;
+
+ /**
+ * Constructor for PBKDF2 implementation object. PBKDF2 parameters must be
+ * passed later.
+ */
+ public PBKDF2Engine()
+ {
+ this.parameters = null;
+ prf = null;
+ }
+
+ /**
+ * Constructor for PBKDF2 implementation object. PBKDF2 parameters are passed
+ * so that this implementation knows iteration count, method to use and
+ * String encoding.
+ *
+ * @param parameters
+ * Data holder for iteration count, method to use et cetera.
+ */
+ public PBKDF2Engine(PBKDF2Parameters parameters)
+ {
+ this.parameters = parameters;
+ prf = null;
+ }
+
+ /**
+ * Constructor for PBKDF2 implementation object. PBKDF2 parameters are passed
+ * so that this implementation knows iteration count, method to use and
+ * String encoding.
+ *
+ * @param parameters
+ * Data holder for iteration count, method to use et cetera.
+ * @param prf
+ * Supply customer Pseudo Random Function.
+ */
+ public PBKDF2Engine(PBKDF2Parameters parameters, PRF prf)
+ {
+ this.parameters = parameters;
+ this.prf = prf;
+ }
+
+ public byte[] deriveKey(String inputPassword)
+ {
+ return deriveKey(inputPassword, 0);
+ }
+
+ public byte[] deriveKey(String inputPassword, int dkLen)
+ {
+ byte[] r = null;
+ byte P[] = null;
+ String charset = parameters.getHashCharset();
+ if (inputPassword == null)
+ {
+ inputPassword = "";
+ }
+ try
+ {
+ if (charset == null)
+ {
+ P = inputPassword.getBytes();
+ }
+ else
+ {
+ P = inputPassword.getBytes(charset);
+ }
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new RuntimeException(e);
+ }
+ assertPRF(P);
+ if (dkLen == 0)
+ {
+ dkLen = prf.getHLen();
+ }
+ r = PBKDF2(prf, parameters.getSalt(), parameters.getIterationCount(), dkLen);
+ return r;
+ }
+
+ public boolean verifyKey(String inputPassword)
+ {
+ byte[] referenceKey = getParameters().getDerivedKey();
+ if (referenceKey == null || referenceKey.length == 0)
+ {
+ return false;
+ }
+ byte[] inputKey = deriveKey(inputPassword, referenceKey.length);
+
+ if (inputKey == null || inputKey.length != referenceKey.length)
+ {
+ return false;
+ }
+ for (int i = 0; i < inputKey.length; i++)
+ {
+ if (inputKey[i] != referenceKey[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Factory method. Default implementation is (H)MAC-based. To be overridden
+ * in derived classes.
+ *
+ * @param P
+ * User-supplied candidate password as array of bytes.
+ */
+ protected void assertPRF(byte[] P)
+ {
+ if (prf == null)
+ {
+ prf = new MacBasedPRF(parameters.getHashAlgorithm());
+ }
+ prf.init(P);
+ }
+
+ public PRF getPseudoRandomFunction()
+ {
+ return prf;
+ }
+
+ /**
+ * Core Password Based Key Derivation Function 2.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2</a>
+ * @param prf
+ * Pseudo Random Function (i.e. HmacSHA1)
+ * @param S
+ * Salt as array of bytes. <code>null</code> means no salt.
+ * @param c
+ * Iteration count (see RFC 2898 4.2)
+ * @param dkLen
+ * desired length of derived key.
+ * @return internal byte array
+ */
+ protected byte[] PBKDF2(PRF prf, byte[] S, int c, int dkLen)
+ {
+ if (S == null)
+ {
+ S = new byte[0];
+ }
+ int hLen = prf.getHLen();
+ int l = ceil(dkLen, hLen);
+ int r = dkLen - (l - 1) * hLen;
+ byte T[] = new byte[l * hLen];
+ int ti_offset = 0;
+ for (int i = 1; i <= l; i++)
+ {
+ _F(T, ti_offset, prf, S, c, i);
+ ti_offset += hLen;
+ }
+ if (r < hLen)
+ {
+ // Incomplete last block
+ byte DK[] = new byte[dkLen];
+ System.arraycopy(T, 0, DK, 0, dkLen);
+ return DK;
+ }
+ return T;
+ }
+
+ /**
+ * Integer division with ceiling function.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step 2.</a>
+ * @param a
+ * @param b
+ * @return ceil(a/b)
+ */
+ protected int ceil(int a, int b)
+ {
+ int m = 0;
+ if (a % b > 0)
+ {
+ m = 1;
+ }
+ return a / b + m;
+ }
+
+ /**
+ * Function F.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step 3.</a>
+ * @param dest
+ * Destination byte buffer
+ * @param offset
+ * Offset into destination byte buffer
+ * @param prf
+ * Pseudo Random Function
+ * @param S
+ * Salt as array of bytes
+ * @param c
+ * Iteration count
+ * @param blockIndex
+ */
+ protected void _F(byte[] dest, int offset, PRF prf, byte[] S, int c, int blockIndex)
+ {
+ int hLen = prf.getHLen();
+ byte U_r[] = new byte[hLen];
+
+ // U0 = S || INT (i);
+ byte U_i[] = new byte[S.length + 4];
+ System.arraycopy(S, 0, U_i, 0, S.length);
+ INT(U_i, S.length, blockIndex);
+
+ for (int i = 0; i < c; i++)
+ {
+ U_i = prf.doFinal(U_i);
+ xor(U_r, U_i);
+ }
+ System.arraycopy(U_r, 0, dest, offset, hLen);
+ }
+
+ /**
+ * Block-Xor. Xor source bytes into destination byte buffer. Destination
+ * buffer must be same length or less than source buffer.
+ *
+ * @param dest
+ * @param src
+ */
+ protected void xor(byte[] dest, byte[] src)
+ {
+ for (int i = 0; i < dest.length; i++)
+ {
+ dest[i] ^= src[i];
+ }
+ }
+
+ /**
+ * Four-octet encoding of the integer i, most significant octet first.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step 3.</a>
+ * @param dest
+ * @param offset
+ * @param i
+ */
+ protected void INT(byte[] dest, int offset, int i)
+ {
+ dest[offset + 0] = (byte) (i / (256 * 256 * 256));
+ dest[offset + 1] = (byte) (i / (256 * 256));
+ dest[offset + 2] = (byte) (i / (256));
+ dest[offset + 3] = (byte) (i);
+ }
+
+ public PBKDF2Parameters getParameters()
+ {
+ return parameters;
+ }
+
+ public void setParameters(PBKDF2Parameters parameters)
+ {
+ this.parameters = parameters;
+ }
+
+ public void setPseudoRandomFunction(PRF prf)
+ {
+ this.prf = prf;
+ }
+}
Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,57 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ *
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public interface PBKDF2Formatter
+{
+ /**
+ * Convert parameters to String.
+ *
+ * @param p
+ * Parameters object to output.
+ * @return String representation
+ */
+ public abstract String toString(PBKDF2Parameters p);
+
+ /**
+ * Convert String to parameters. Depending on actual implementation, it may
+ * be required to set further fields externally.
+ *
+ * @param s
+ * String representation of parameters to decode.
+ * @return <code>false</code> syntax OK, <code>true</code> some syntax
+ * issue.
+ */
+ public abstract boolean fromString(PBKDF2Parameters p, String s);
+}
\ No newline at end of file
Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,68 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ *
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public class PBKDF2HexFormatter implements PBKDF2Formatter
+{
+ public boolean fromString(PBKDF2Parameters p, String s)
+ {
+ if (p == null || s == null)
+ {
+ return true;
+ }
+
+ String[] p123 = s.split(":");
+ if (p123 == null || p123.length != 3)
+ {
+ return true;
+ }
+
+ byte salt[] = BinTools.hex2bin(p123[0]);
+ int iterationCount = Integer.parseInt(p123[1]);
+ byte bDK[] = BinTools.hex2bin(p123[2]);
+
+ p.setSalt(salt);
+ p.setIterationCount(iterationCount);
+ p.setDerivedKey(bDK);
+ return false;
+ }
+
+ public String toString(PBKDF2Parameters p)
+ {
+ String s = BinTools.bin2hex(p.getSalt()) + ":"
+ + String.valueOf(p.getIterationCount()) + ":"
+ + BinTools.bin2hex(p.getDerivedKey());
+ return s;
+ }
+}
\ No newline at end of file
Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,165 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ *
+ * <p>
+ * Parameter data holder for PBKDF2 configuration.
+ * </p>
+ *
+ * <hr />
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public class PBKDF2Parameters
+{
+ protected byte[] salt;
+
+ protected int iterationCount;
+
+ protected String hashAlgorithm;
+
+ protected String hashCharset;
+
+ /**
+ * The derived key is actually only a convenience to store a reference
+ * derived key. It is not used during computation.
+ */
+ protected byte[] derivedKey;
+
+ /**
+ * Constructor. Defaults to <code>null</code> for byte arrays, UTF-8 as
+ * character set and 1000 for iteration count.
+ *
+ */
+ public PBKDF2Parameters()
+ {
+ this.hashAlgorithm = null;
+ this.hashCharset = "UTF-8";
+ this.salt = null;
+ this.iterationCount = 1000;
+ this.derivedKey = null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param hashAlgorithm
+ * for example HMacSHA1 or HMacMD5
+ * @param hashCharset
+ * for example UTF-8
+ * @param salt
+ * Salt as byte array, may be <code>null</code> (not recommended)
+ * @param iterationCount
+ * Number of iterations to execute. Recommended value 1000.
+ */
+ public PBKDF2Parameters(String hashAlgorithm, String hashCharset, byte[] salt, int iterationCount)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashCharset = hashCharset;
+ this.salt = salt;
+ this.iterationCount = iterationCount;
+ this.derivedKey = null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param hashAlgorithm
+ * for example HMacSHA1 or HMacMD5
+ * @param hashCharset
+ * for example UTF-8
+ * @param salt
+ * Salt as byte array, may be <code>null</code> (not recommended)
+ * @param iterationCount
+ * Number of iterations to execute. Recommended value 1000.
+ * @param derivedKey
+ * Convenience data holder, not used during computation.
+ */
+ public PBKDF2Parameters(String hashAlgorithm, String hashCharset, byte[] salt, int iterationCount, byte[] derivedKey)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashCharset = hashCharset;
+ this.salt = salt;
+ this.iterationCount = iterationCount;
+ this.derivedKey = derivedKey;
+ }
+
+ public int getIterationCount()
+ {
+ return iterationCount;
+ }
+
+ public void setIterationCount(int iterationCount)
+ {
+ this.iterationCount = iterationCount;
+ }
+
+ public byte[] getSalt()
+ {
+ return salt;
+ }
+
+ public void setSalt(byte[] salt)
+ {
+ this.salt = salt;
+ }
+
+ public byte[] getDerivedKey()
+ {
+ return derivedKey;
+ }
+
+ public void setDerivedKey(byte[] derivedKey)
+ {
+ this.derivedKey = derivedKey;
+ }
+
+ public String getHashAlgorithm()
+ {
+ return hashAlgorithm;
+ }
+
+ public void setHashAlgorithm(String hashAlgorithm)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ }
+
+ public String getHashCharset()
+ {
+ return hashCharset;
+ }
+
+ public void setHashCharset(String hashCharset)
+ {
+ this.hashCharset = hashCharset;
+ }
+}
Added: trunk/src/main/org/jboss/seam/security/crypto/PRF.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PRF.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PRF.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,64 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ *
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
+ * </p>
+ * <p>
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * </p>
+ * <p>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ *
+ * @author Matthias Gärtner
+ * @version 1.0
+ */
+public interface PRF
+{
+ /**
+ * Initialize this instance with the user-supplied password.
+ *
+ * @param P
+ * The password supplied as array of bytes. It is the caller's task
+ * to convert String passwords to bytes as appropriate.
+ */
+ public void init(byte[] P);
+
+ /**
+ * Pseudo Random Function
+ *
+ * @param M
+ * Input data/message etc. Together with any data supplied during
+ * initilization.
+ * @return Random bytes of hLen length.
+ */
+ public byte[] doFinal(byte[] M);
+
+ /**
+ * Query block size of underlying algorithm/mechanism.
+ *
+ * @return block size
+ */
+ public int getHLen();
+}
\ No newline at end of file
Modified: trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java 2009-04-14 23:58:24 UTC (rev 10418)
+++ trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -43,8 +43,8 @@
import org.jboss.seam.security.Identity;
import org.jboss.seam.security.Role;
import org.jboss.seam.security.SimplePrincipal;
+import org.jboss.seam.security.crypto.BinTools;
import org.jboss.seam.util.AnnotatedBeanProperty;
-import org.jboss.seam.util.Base64;
import org.jboss.seam.util.TypedBeanProperty;
/**
@@ -254,7 +254,7 @@
if (passwordSaltProperty.isSet())
{
byte[] salt = generateUserSalt(user);
- passwordSaltProperty.setValue(user, Base64.encodeBytes(salt));
+ passwordSaltProperty.setValue(user, BinTools.bin2hex(salt));
userPasswordProperty.setValue(user, generatePasswordHash(password, salt));
}
else
@@ -821,7 +821,7 @@
", but it contains no value");
}
- passwordHash = generatePasswordHash(password, Base64.decode(encodedSalt));
+ passwordHash = generatePasswordHash(password, BinTools.hex2bin(encodedSalt));
}
else
{
Modified: trunk/src/main/org/jboss/seam/security/management/PasswordHash.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/PasswordHash.java 2009-04-14 23:58:24 UTC (rev 10418)
+++ trunk/src/main/org/jboss/seam/security/management/PasswordHash.java 2009-04-15 06:41:04 UTC (rev 10419)
@@ -10,7 +10,6 @@
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.SecretKeySpec;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
@@ -18,6 +17,10 @@
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.security.crypto.BinTools;
+import org.jboss.seam.security.crypto.PBKDF2;
+import org.jboss.seam.security.crypto.PBKDF2Engine;
+import org.jboss.seam.security.crypto.PBKDF2Parameters;
import org.jboss.seam.util.Base64;
/**
@@ -36,7 +39,15 @@
private static final String DEFAULT_ALGORITHM = ALGORITHM_MD5;
- private int saltLength = 8; // default password salt length, in bytes
+ /*
+ * If specified, use the JCE instead of the built in algorithm
+ */
+ private String hashAlgorithm = null;
+
+ /*
+ * default password salt length, in bytes
+ */
+ private int saltLength = 8;
@Deprecated
public String generateHash(String password)
@@ -100,12 +111,20 @@
public String createPasswordKey(char[] password, byte[] salt, int iterations)
throws GeneralSecurityException
{
- PBEKeySpec passwordKeySpec = new PBEKeySpec(password, salt, iterations, 256);
- SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
- SecretKey passwordKey = secretKeyFactory.generateSecret(passwordKeySpec);
- passwordKeySpec.clearPassword();
- byte[] encoded = passwordKey.getEncoded();
- return Base64.encodeBytes(new SecretKeySpec(encoded, "AES").getEncoded());
+ if (hashAlgorithm != null)
+ {
+ PBEKeySpec passwordKeySpec = new PBEKeySpec(password, salt, iterations, 256);
+ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(hashAlgorithm);
+ SecretKey passwordKey = secretKeyFactory.generateSecret(passwordKeySpec);
+ passwordKeySpec.clearPassword();
+ return BinTools.bin2hex(passwordKey.getEncoded());
+ }
+ else
+ {
+ PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA1", "ISO-8859-1", salt, iterations);
+ PBKDF2 pbkdf2 = new PBKDF2Engine(params);
+ return BinTools.bin2hex(pbkdf2.deriveKey(new String(password)));
+ }
}
public static PasswordHash instance()
@@ -113,6 +132,16 @@
return (PasswordHash) Component.getInstance(PasswordHash.class, ScopeType.STATELESS);
}
+ public String getHashAlgorithm()
+ {
+ return hashAlgorithm;
+ }
+
+ public void setHashAlgorithm(String hashAlgorithm)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ }
+
public int getSaltLength()
{
return saltLength;
15 years, 7 months
Seam SVN: r10418 - in trunk/examples/seamspace: resources/WEB-INF and 3 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-04-14 19:58:24 -0400 (Tue, 14 Apr 2009)
New Revision: 10418
Added:
trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java
trunk/examples/seamspace/view/hashgen.xhtml
Modified:
trunk/examples/seamspace/resources/WEB-INF/pages.xml
trunk/examples/seamspace/resources/import.sql
trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/MemberAccount.java
trunk/examples/seamspace/view/home.xhtml
trunk/examples/seamspace/view/style/seamspace.css
Log:
added @PasswordSalt to account entity, added hash generator page
Modified: trunk/examples/seamspace/resources/WEB-INF/pages.xml
===================================================================
--- trunk/examples/seamspace/resources/WEB-INF/pages.xml 2009-04-14 23:56:22 UTC (rev 10417)
+++ trunk/examples/seamspace/resources/WEB-INF/pages.xml 2009-04-14 23:58:24 UTC (rev 10418)
@@ -6,12 +6,9 @@
<page view-id="/home.xhtml">
<navigation from-action="#{identity.login}">
- <!--rule if-outcome="loggedIn">
- <redirect view-id="/profile.xhtml"/>
- </rule-->
- <rule if="#{identity.loggedIn and authenticatedMember ne null}">
- <redirect view-id="/profile.xhtml"/>
- </rule>
+ <rule if="#{identity.loggedIn and authenticatedMember ne null}">
+ <redirect view-id="/profile.xhtml"/>
+ </rule>
</navigation>
<navigation from-action="#{register.start}">
<redirect view-id="/register.xhtml"/>
Modified: trunk/examples/seamspace/resources/import.sql
===================================================================
--- trunk/examples/seamspace/resources/import.sql 2009-04-14 23:56:22 UTC (rev 10417)
+++ trunk/examples/seamspace/resources/import.sql 2009-04-14 23:58:24 UTC (rev 10418)
@@ -7,10 +7,10 @@
insert into MemberRole (roleid, name, conditional) values (2, 'admin', false);
insert into MemberRole (roleid, name, conditional) values (3, 'friends', true);
-insert into MemberAccount (accountid, username, passwordhash, enabled, member_id) values (1, 'demo', '/9Se/pfHeUH8FJ4asBD6jQ==', 1, 1);
-insert into MemberAccount (accountid, username, passwordhash, enabled, member_id) values (2, 'duke', 'lykcKcxppliQQk0Pl9so8g==', 1, 2);
-insert into MemberAccount (accountid, username, passwordhash, enabled, member_id) values (3, 'shadowman', '12rNoz/P7eYqiml534jmkA==', 1, 3);
-insert into MemberAccount (accountid, username, passwordhash, enabled, member_id) values (4, 'mona', 'Cnrf5YBxOY4VtRd/Ss6Ekw==', 1, 4);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (1, 'demo', 'Lb9y5+2nJZ6M4dI9d1Fjy60G21jn9SCY3mpWu4AodsI=', 'dNrc6UsJxXo=', 1, 1);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (2, 'duke', 'Ci9yZp93B/Ig/ElmuBjbq7ldpLp5Dh0Qh4YTP7iquKY=', 'lyEG5QdmTME=', 1, 2);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (3, 'shadowman', 'vNY1tLpId6KQLeTXEB4yShDAyAlwV4BvfPq11HpBHzM=', 'kKBf7ZH3DDk=', 1, 3);
+insert into MemberAccount (accountid, username, passwordhash, passwordsalt, enabled, member_id) values (4, 'mona', 'Vgt0PPvkzacu4qeLYF3USIpN79blPo5TR2JYm0Ak9xA=', 'BM0mitVT6Gg=', 1, 4);
insert into AccountMembership (accountid, memberof) values (1, 2);
insert into AccountMembership (accountid, memberof) values (2, 1);
Added: trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java
===================================================================
--- trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java (rev 0)
+++ trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/HashGenerator.java 2009-04-14 23:58:24 UTC (rev 10418)
@@ -0,0 +1,57 @@
+package org.jboss.seam.example.seamspace;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.security.management.JpaIdentityStore;
+import org.jboss.seam.security.management.PasswordHash;
+import org.jboss.seam.util.Base64;
+
+(a)Scope(ScopeType.EVENT)
+@Name("hashgenerator")
+public class HashGenerator
+{
+ @In JpaIdentityStore identityStore;
+
+ private String password;
+ private String passwordHash;
+ private String passwordSalt;
+
+ public String getPassword()
+ {
+ return password;
+ }
+
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ public String getPasswordHash()
+ {
+ return passwordHash;
+ }
+
+ public void setPasswordHash(String passwordHash)
+ {
+ this.passwordHash = passwordHash;
+ }
+
+ public String getPasswordSalt()
+ {
+ return passwordSalt;
+ }
+
+ public void setPasswordSalt(String passwordSalt)
+ {
+ this.passwordSalt = passwordSalt;
+ }
+
+ public void generate()
+ {
+ byte[] salt = PasswordHash.instance().generateRandomSalt();
+ passwordSalt = Base64.encodeBytes(salt);
+ passwordHash = identityStore.generatePasswordHash(password, salt);
+ }
+}
Modified: trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/MemberAccount.java
===================================================================
--- trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/MemberAccount.java 2009-04-14 23:56:22 UTC (rev 10417)
+++ trunk/examples/seamspace/src/org/jboss/seam/example/seamspace/MemberAccount.java 2009-04-14 23:58:24 UTC (rev 10418)
@@ -14,6 +14,7 @@
import javax.persistence.UniqueConstraint;
import org.hibernate.validator.NotNull;
+import org.jboss.seam.annotations.security.management.PasswordSalt;
import org.jboss.seam.annotations.security.management.UserEnabled;
import org.jboss.seam.annotations.security.management.UserPassword;
import org.jboss.seam.annotations.security.management.UserPrincipal;
@@ -28,6 +29,7 @@
private Integer accountId;
private String username;
private String passwordHash;
+ private String passwordSalt;
private boolean enabled;
private Set<MemberRole> roles;
@@ -55,7 +57,7 @@
this.username = username;
}
- @UserPassword(hash = "MD5")
+ @UserPassword
public String getPasswordHash()
{
return passwordHash;
@@ -64,8 +66,19 @@
public void setPasswordHash(String passwordHash)
{
this.passwordHash = passwordHash;
- }
+ }
+ @PasswordSalt
+ public String getPasswordSalt()
+ {
+ return passwordSalt;
+ }
+
+ public void setPasswordSalt(String passwordSalt)
+ {
+ this.passwordSalt = passwordSalt;
+ }
+
@UserEnabled
public boolean isEnabled()
{
Added: trunk/examples/seamspace/view/hashgen.xhtml
===================================================================
--- trunk/examples/seamspace/view/hashgen.xhtml (rev 0)
+++ trunk/examples/seamspace/view/hashgen.xhtml 2009-04-14 23:58:24 UTC (rev 10418)
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <ui:composition template="template.xhtml">
+ <ui:define name="content">
+ <h1>Password Hash Generator</h1>
+
+ <p>
+ This page uses the methods in JpaIdentityStore to generate password hash values that you can
+ use in your own application's import.sql to create default accounts for your application.
+ </p>
+
+ <p>
+ Please note that you must have a property annotated @PasswordSalt for these hash values to work!
+ </p>
+
+ <h:form>
+
+ <div class="formRow">
+ <h:outputLabel for="password">Enter a password</h:outputLabel>
+ <h:inputText id="password" value="#{hashgenerator.password}" required="true" styleClass="wide"/>
+ <div class="validationError"><h:message for="password"/></div>
+ </div>
+
+ <h:commandButton action="#{hashgenerator.generate}" value="Generate hash"/>
+
+ </h:form>
+
+ <h2>Results</h2>
+
+ <div>Generated hash (base 64 encoded): <pre>#{hashgenerator.passwordHash}</pre></div>
+ <div>Randomly generated password salt (base 64 encoded): <pre>#{hashgenerator.passwordSalt}</pre></div>
+
+ </ui:define>
+
+ </ui:composition>
+</html>
Modified: trunk/examples/seamspace/view/home.xhtml
===================================================================
--- trunk/examples/seamspace/view/home.xhtml 2009-04-14 23:56:22 UTC (rev 10417)
+++ trunk/examples/seamspace/view/home.xhtml 2009-04-14 23:58:24 UTC (rev 10418)
@@ -15,6 +15,10 @@
been put together to demonstrate the various features of the Seam Security API.
</p>
+ <p><b>New!</b> You can now use the <s:link view="/hashgen.xhtml" value="Password Hash Generator"/>
+ page to generate password hashes for your own application.
+ </p>
+
</div>
<div id="contentDivider">
Modified: trunk/examples/seamspace/view/style/seamspace.css
===================================================================
--- trunk/examples/seamspace/view/style/seamspace.css 2009-04-14 23:56:22 UTC (rev 10417)
+++ trunk/examples/seamspace/view/style/seamspace.css 2009-04-14 23:58:24 UTC (rev 10418)
@@ -447,10 +447,6 @@
padding: 8px 4px 8px 12px;
}
-div.formRow {
- padding: 3px 4px 3px 2px;
-}
-
form.register label {
float: left;
display: block;
@@ -507,8 +503,7 @@
/* General form styles */
div.formRow {
- padding-top: 2px;
- padding-bottom: 2px;
+ padding: 3px 4px 3px 2px;
clear: both;
}
15 years, 7 months
Seam SVN: r10417 - in trunk/src/main/org/jboss/seam: security/management and 1 other directory.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-04-14 19:56:22 -0400 (Tue, 14 Apr 2009)
New Revision: 10417
Added:
trunk/src/main/org/jboss/seam/annotations/security/management/PasswordSalt.java
Modified:
trunk/src/main/org/jboss/seam/annotations/security/management/UserPassword.java
trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
trunk/src/main/org/jboss/seam/security/management/PasswordHash.java
Log:
JBSEAM-3762
Added: trunk/src/main/org/jboss/seam/annotations/security/management/PasswordSalt.java
===================================================================
--- trunk/src/main/org/jboss/seam/annotations/security/management/PasswordSalt.java (rev 0)
+++ trunk/src/main/org/jboss/seam/annotations/security/management/PasswordSalt.java 2009-04-14 23:56:22 UTC (rev 10417)
@@ -0,0 +1,24 @@
+package org.jboss.seam.annotations.security.management;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * The salt value used to produce the password hash
+ *
+ * @author Shane Bryzak
+ */
+@Target({METHOD,FIELD})
+@Documented
+@Retention(RUNTIME)
+@Inherited
+public @interface PasswordSalt
+{
+
+}
Modified: trunk/src/main/org/jboss/seam/annotations/security/management/UserPassword.java
===================================================================
--- trunk/src/main/org/jboss/seam/annotations/security/management/UserPassword.java 2009-04-14 21:36:54 UTC (rev 10416)
+++ trunk/src/main/org/jboss/seam/annotations/security/management/UserPassword.java 2009-04-14 23:56:22 UTC (rev 10417)
@@ -20,5 +20,13 @@
@Inherited
public @interface UserPassword
{
+ /**
+ * The hash algorithm, only used if there is no @PasswordSalt property specified
+ */
String hash() default "";
+
+ /**
+ * Number of iterations for generating the password hash
+ */
+ int iterations() default 1000;
}
Modified: trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java 2009-04-14 21:36:54 UTC (rev 10416)
+++ trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java 2009-04-14 23:56:22 UTC (rev 10417)
@@ -6,7 +6,9 @@
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.security.GeneralSecurityException;
import java.security.Principal;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -22,6 +24,7 @@
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.annotations.security.management.PasswordSalt;
import org.jboss.seam.annotations.security.management.RoleConditional;
import org.jboss.seam.annotations.security.management.RoleGroups;
import org.jboss.seam.annotations.security.management.RoleName;
@@ -41,6 +44,7 @@
import org.jboss.seam.security.Role;
import org.jboss.seam.security.SimplePrincipal;
import org.jboss.seam.util.AnnotatedBeanProperty;
+import org.jboss.seam.util.Base64;
import org.jboss.seam.util.TypedBeanProperty;
/**
@@ -76,6 +80,7 @@
private AnnotatedBeanProperty<UserPrincipal> userPrincipalProperty;
private AnnotatedBeanProperty<UserPassword> userPasswordProperty;
+ private AnnotatedBeanProperty<PasswordSalt> passwordSaltProperty;
private AnnotatedBeanProperty<UserRoles> userRolesProperty;
private AnnotatedBeanProperty<UserEnabled> userEnabledProperty;
private AnnotatedBeanProperty<UserFirstName> userFirstNameProperty;
@@ -126,6 +131,7 @@
{
userPrincipalProperty = new AnnotatedBeanProperty(userClass, UserPrincipal.class);
userPasswordProperty = new AnnotatedBeanProperty(userClass, UserPassword.class);
+ passwordSaltProperty = new AnnotatedBeanProperty(userClass, PasswordSalt.class);
userRolesProperty = new AnnotatedBeanProperty(userClass, UserRoles.class);
userEnabledProperty = new AnnotatedBeanProperty(userClass, UserEnabled.class);
userFirstNameProperty = new AnnotatedBeanProperty(userClass, UserFirstName.class);
@@ -217,8 +223,8 @@
if (userEnabledProperty.isSet()) userEnabledProperty.setValue(user, false);
}
else
- {
- userPasswordProperty.setValue(user, generatePasswordHash(password, getUserAccountSalt(user)));
+ {
+ setUserPassword(user, password);
if (userEnabledProperty.isSet()) userEnabledProperty.setValue(user, true);
}
@@ -243,12 +249,38 @@
}
}
+ protected void setUserPassword(Object user, String password)
+ {
+ if (passwordSaltProperty.isSet())
+ {
+ byte[] salt = generateUserSalt(user);
+ passwordSaltProperty.setValue(user, Base64.encodeBytes(salt));
+ userPasswordProperty.setValue(user, generatePasswordHash(password, salt));
+ }
+ else
+ {
+ userPasswordProperty.setValue(user, generatePasswordHash(password, getUserAccountSalt(user)));
+ }
+ }
+
+ /**
+ * @deprecated Use JpaIdentityStore.generateRandomSalt(Object) instead
+ */
+ @Deprecated
protected String getUserAccountSalt(Object user)
- {
+ {
// By default, we'll use the user's username as the password salt
return userPrincipalProperty.getValue(user).toString();
}
+ /**
+ * Generates a 64 bit random salt value
+ */
+ public byte[] generateUserSalt(Object user)
+ {
+ return PasswordHash.instance().generateRandomSalt();
+ }
+
public boolean createUser(String username, String password)
{
return createUser(username, password, null, null);
@@ -361,8 +393,6 @@
}
}
- mergeEntity(user);
-
return true;
}
@@ -399,8 +429,7 @@
}
}
}
-
- if (success) mergeEntity(user);
+
return success;
}
@@ -420,7 +449,6 @@
throw new NoSuchRoleException("Could not grant role, group '" + group + "' does not exist");
}
-
Collection roleGroups = (Collection) roleGroupsProperty.getValue(targetRole);
if (roleGroups == null)
{
@@ -452,7 +480,6 @@
}
((Collection) roleGroupsProperty.getValue(targetRole)).add(targetGroup);
- mergeEntity(targetRole);
return true;
}
@@ -474,8 +501,6 @@
}
boolean success = ((Collection) roleGroupsProperty.getValue(roleToRemove)).remove(targetGroup);
-
- if (success) mergeEntity(roleToRemove);
return success;
}
@@ -565,8 +590,7 @@
return false;
}
- userEnabledProperty.setValue(user, true);
- mergeEntity(user);
+ userEnabledProperty.setValue(user, true);
return true;
}
@@ -590,9 +614,7 @@
return false;
}
- userEnabledProperty.setValue(user, false);
- mergeEntity(user);
-
+ userEnabledProperty.setValue(user, false);
return true;
}
@@ -604,8 +626,8 @@
throw new NoSuchUserException("Could not change password, user '" + username + "' does not exist");
}
- userPasswordProperty.setValue(user, generatePasswordHash(password, getUserAccountSalt(user)));
- mergeEntity(user);
+ setUserPassword(user, password);
+
return true;
}
@@ -723,8 +745,33 @@
}
}
+ public String generatePasswordHash(String password, byte[] salt)
+ {
+ if (passwordSaltProperty.isSet())
+ {
+ try
+ {
+ return PasswordHash.instance().createPasswordKey(password.toCharArray(), salt,
+ userPasswordProperty.getAnnotation().iterations());
+ }
+ catch (GeneralSecurityException ex)
+ {
+ throw new IdentityManagementException("Exception generating password hash", ex);
+ }
+ }
+ else
+ {
+ return generatePasswordHash(password, new String(salt));
+ }
+ }
+
+ /**
+ *
+ * @deprecated Use JpaIdentityStore.generatePasswordHash(String, byte[]) instead
+ */
+ @Deprecated
protected String generatePasswordHash(String password, String salt)
- {
+ {
String algorithm = userPasswordProperty.getAnnotation().hash();
if (algorithm == null || "".equals(algorithm))
@@ -752,7 +799,7 @@
{
return PasswordHash.instance().generateSaltedHash(password, salt, algorithm);
}
- }
+ }
}
public boolean authenticate(String username, String password)
@@ -763,7 +810,25 @@
return false;
}
- String passwordHash = generatePasswordHash(password, getUserAccountSalt(user));
+ String passwordHash = null;
+
+ if (passwordSaltProperty.isSet())
+ {
+ String encodedSalt = (String) passwordSaltProperty.getValue(user);
+ if (encodedSalt == null)
+ {
+ throw new IdentityManagementException("A @PasswordSalt property was found on entity " + user +
+ ", but it contains no value");
+ }
+
+ passwordHash = generatePasswordHash(password, Base64.decode(encodedSalt));
+ }
+ else
+ {
+ passwordHash = generatePasswordHash(password, getUserAccountSalt(user));
+ }
+
+
boolean success = passwordHash.equals(userPasswordProperty.getValue(user));
if (success && Events.exists())
Modified: trunk/src/main/org/jboss/seam/security/management/PasswordHash.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/PasswordHash.java 2009-04-14 21:36:54 UTC (rev 10416)
+++ trunk/src/main/org/jboss/seam/security/management/PasswordHash.java 2009-04-14 23:56:22 UTC (rev 10417)
@@ -3,8 +3,15 @@
import static org.jboss.seam.ScopeType.STATELESS;
import static org.jboss.seam.annotations.Install.BUILT_IN;
+import java.security.GeneralSecurityException;
import java.security.MessageDigest;
+import java.security.SecureRandom;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Install;
@@ -26,24 +33,33 @@
{
public static final String ALGORITHM_MD5 = "MD5";
public static final String ALGORITHM_SHA = "SHA";
-
+
private static final String DEFAULT_ALGORITHM = ALGORITHM_MD5;
+ private int saltLength = 8; // default password salt length, in bytes
+
+ @Deprecated
public String generateHash(String password)
{
return generateHash(password, DEFAULT_ALGORITHM);
}
+ @Deprecated
public String generateHash(String password, String algorithm)
{
return generateSaltedHash(password, null, algorithm);
}
+ @Deprecated
public String generateSaltedHash(String password, String saltPhrase)
{
return generateSaltedHash(password, saltPhrase, DEFAULT_ALGORITHM);
}
+ /**
+ * @deprecated Use PasswordHash.createPasswordKey() instead
+ */
+ @Deprecated
public String generateSaltedHash(String password, String saltPhrase, String algorithm)
{
try {
@@ -71,8 +87,39 @@
}
}
+ public byte[] generateRandomSalt()
+ {
+ byte[] salt = new byte[saltLength];
+ new SecureRandom().nextBytes(salt);
+ return salt;
+ }
+
+ /**
+ *
+ */
+ public String createPasswordKey(char[] password, byte[] salt, int iterations)
+ throws GeneralSecurityException
+ {
+ PBEKeySpec passwordKeySpec = new PBEKeySpec(password, salt, iterations, 256);
+ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+ SecretKey passwordKey = secretKeyFactory.generateSecret(passwordKeySpec);
+ passwordKeySpec.clearPassword();
+ byte[] encoded = passwordKey.getEncoded();
+ return Base64.encodeBytes(new SecretKeySpec(encoded, "AES").getEncoded());
+ }
+
public static PasswordHash instance()
{
return (PasswordHash) Component.getInstance(PasswordHash.class, ScopeType.STATELESS);
}
+
+ public int getSaltLength()
+ {
+ return saltLength;
+ }
+
+ public void setSaltLength(int saltLength)
+ {
+ this.saltLength = saltLength;
+ }
}
15 years, 7 months
Seam SVN: r10416 - trunk/src/remoting/org/jboss/seam/remoting/wrapper.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-04-14 17:36:54 -0400 (Tue, 14 Apr 2009)
New Revision: 10416
Modified:
trunk/src/remoting/org/jboss/seam/remoting/wrapper/DateWrapper.java
Log:
JBSEAM-4038
Modified: trunk/src/remoting/org/jboss/seam/remoting/wrapper/DateWrapper.java
===================================================================
--- trunk/src/remoting/org/jboss/seam/remoting/wrapper/DateWrapper.java 2009-04-14 21:10:26 UTC (rev 10415)
+++ trunk/src/remoting/org/jboss/seam/remoting/wrapper/DateWrapper.java 2009-04-14 21:36:54 UTC (rev 10416)
@@ -11,73 +11,82 @@
/**
* Handles date conversions
- *
+ *
* @author Shane Bryzak
*/
public class DateWrapper extends BaseWrapper implements Wrapper
{
- private static final byte[] DATE_TAG_OPEN = "<date>".getBytes();
- private static final byte[] DATE_TAG_CLOSE = "</date>".getBytes();
- private static final DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
-
- public void marshal(OutputStream out) throws IOException
- {
- out.write(DATE_TAG_OPEN);
- if (Date.class.isAssignableFrom(value.getClass()))
- {
- out.write(df.format(value).getBytes());
- }
- else if (Calendar.class.isAssignableFrom(value.getClass()))
- {
- out.write(df.format(((Calendar) value).getTime()).getBytes());
- }
- out.write(DATE_TAG_CLOSE);
- }
-
- public Object convert(Type type)
- throws ConversionException
- {
- if ((type instanceof Class && Date.class.isAssignableFrom((Class) type)) ||
- type.equals(Object.class))
- {
- try {
- value = df.parse(element.getStringValue());
+ private static final byte[] DATE_TAG_OPEN = "<date>".getBytes();
+ private static final byte[] DATE_TAG_CLOSE = "</date>".getBytes();
+
+ private static final String DATE_FORMAT = "yyyyMMddHHmmssSSS";
+
+ private DateFormat getDateFormat()
+ {
+ return new SimpleDateFormat(DATE_FORMAT);
+ }
+
+ public void marshal(OutputStream out) throws IOException
+ {
+ out.write(DATE_TAG_OPEN);
+ if (Date.class.isAssignableFrom(value.getClass()))
+ {
+ out.write(getDateFormat().format(value).getBytes());
}
- catch (ParseException ex)
+ else if (Calendar.class.isAssignableFrom(value.getClass()))
{
- throw new ConversionException(String.format(
- "Date value [%s] is not in a valid format.", element.getStringValue()));
+ out.write(getDateFormat().format(((Calendar) value).getTime()).getBytes());
}
- }
- else if ((type instanceof Class && Calendar.class.isAssignableFrom((Class) type)))
- {
- try
- {
- Calendar cal = Calendar.getInstance();
- cal.setTime(df.parse(element.getStringValue()));
- value = cal;
- }
- catch (ParseException ex)
- {
- throw new ConversionException(String.format(
- "Date value [%s] is not in a valid format.", element.getStringValue()));
- }
- }
- else
- throw new ConversionException(String.format(
- "Value [%s] cannot be converted to type [%s].", element.getStringValue(),
- type));
-
- return value;
- }
-
- public ConversionScore conversionScore(Class cls)
- {
- if (Date.class.isAssignableFrom(cls) || Calendar.class.isAssignableFrom(cls))
- return ConversionScore.exact;
- else if (cls.equals(Object.class))
- return ConversionScore.compatible;
- else
- return ConversionScore.nomatch;
- }
+ out.write(DATE_TAG_CLOSE);
+ }
+
+ public Object convert(Type type) throws ConversionException
+ {
+ if ((type instanceof Class && Date.class.isAssignableFrom((Class) type)) || type.equals(Object.class))
+ {
+ try
+ {
+ value = getDateFormat().parse(element.getStringValue());
+ }
+ catch (ParseException ex)
+ {
+ throw new ConversionException(String.format("Date value [%s] is not in a valid format.", element.getStringValue()));
+ }
+ }
+ else if ((type instanceof Class && Calendar.class.isAssignableFrom((Class) type)))
+ {
+ try
+ {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(getDateFormat().parse(element.getStringValue()));
+ value = cal;
+ }
+ catch (ParseException ex)
+ {
+ throw new ConversionException(String.format("Date value [%s] is not in a valid format.", element.getStringValue()));
+ }
+ }
+ else
+ {
+ throw new ConversionException(String.format("Value [%s] cannot be converted to type [%s].", element.getStringValue(), type));
+ }
+
+ return value;
+ }
+
+ public ConversionScore conversionScore(Class cls)
+ {
+ if (Date.class.isAssignableFrom(cls) || Calendar.class.isAssignableFrom(cls))
+ {
+ return ConversionScore.exact;
+ }
+ else if (cls.equals(Object.class))
+ {
+ return ConversionScore.compatible;
+ }
+ else
+ {
+ return ConversionScore.nomatch;
+ }
+ }
}
15 years, 7 months
Seam SVN: r10415 - trunk/src/main/org/jboss/seam/security.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-04-14 17:10:26 -0400 (Tue, 14 Apr 2009)
New Revision: 10415
Modified:
trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java
Log:
interceptor invoked within RollbackInterceptor
Modified: trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java 2009-04-14 20:47:12 UTC (rev 10414)
+++ trunk/src/main/org/jboss/seam/security/SecurityInterceptor.java 2009-04-14 21:10:26 UTC (rev 10415)
@@ -17,6 +17,7 @@
import org.jboss.seam.async.AsynchronousInterceptor;
import org.jboss.seam.intercept.AbstractInterceptor;
import org.jboss.seam.intercept.InvocationContext;
+import org.jboss.seam.transaction.RollbackInterceptor;
import org.jboss.seam.util.Strings;
/**
@@ -25,7 +26,7 @@
* @author Shane Bryzak
*/
@Interceptor(type=InterceptorType.CLIENT,
- around=AsynchronousInterceptor.class)
+ around=AsynchronousInterceptor.class, within = RollbackInterceptor.class)
public class SecurityInterceptor extends AbstractInterceptor implements Serializable
{
private static final long serialVersionUID = -6567750187000766925L;
15 years, 7 months
Seam SVN: r10414 - trunk/examples/ui/src/org/jboss/seam/example/ui.
by seam-commits@lists.jboss.org
Author: danielc.roth
Date: 2009-04-14 16:47:12 -0400 (Tue, 14 Apr 2009)
New Revision: 10414
Modified:
trunk/examples/ui/src/org/jboss/seam/example/ui/Resources.java
Log:
Fix for JBSEAM-4113
Modified: trunk/examples/ui/src/org/jboss/seam/example/ui/Resources.java
===================================================================
--- trunk/examples/ui/src/org/jboss/seam/example/ui/Resources.java 2009-04-14 20:45:29 UTC (rev 10413)
+++ trunk/examples/ui/src/org/jboss/seam/example/ui/Resources.java 2009-04-14 20:47:12 UTC (rev 10414)
@@ -1,8 +1,6 @@
package org.jboss.seam.example.ui;
import java.io.ByteArrayInputStream;
-import java.util.HashMap;
-import java.util.Map;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
@@ -14,30 +12,30 @@
@Scope(ScopeType.EVENT)
public class Resources
{
-
- private static Map<String, ResourceItem> resources = new HashMap<String, ResourceItem>();
-
- static
- {
- resources.put("1", new ResourceItem("text.txt", new byte[] { 'a', 'b', 'c' }, null, "text/plain"));
- ByteArrayInputStream str = new ByteArrayInputStream(new byte[] { '1', '2', '3' });
- resources.put("2", new ResourceItem("numbers.txt", str, null, "text/plain"));
- }
-
+
@RequestParameter
- private String id;
-
+ private int id;
+
private ResourceItem item;
-
+
@Create
public void create()
{
- item = resources.get(id);
+ switch (id)
+ {
+ case 1:
+ item = new ResourceItem("text.txt", new byte[] { 'a', 'b', 'c' }, null, "text/plain");
+ break;
+ case 2:
+ ByteArrayInputStream str = new ByteArrayInputStream(new byte[] { '1', '2', '3' });
+ item = new ResourceItem("numbers.txt", str, null, "text/plain");
+ break;
+ }
}
-
+
public static class ResourceItem
{
-
+
public ResourceItem(String fileName, Object data, String disposition, String contentType)
{
this.fileName = fileName;
@@ -45,57 +43,52 @@
this.disposition = disposition;
this.contentType = contentType;
}
-
+
public String fileName;
public Object data;
public String disposition;
public String contentType;
-
+
public String getFileName()
{
return fileName;
}
-
+
public Object getData()
{
return data;
}
-
+
public String getDisposition()
{
return disposition;
}
-
+
public String getContentType()
{
return contentType;
}
-
+
}
-
- public String getId()
+
+ public int getId()
{
return id;
}
-
- public void setId(String id)
+
+ public void setId(int id)
{
this.id = id;
}
-
+
public ResourceItem getItem()
{
return item;
}
-
+
public void setItem(ResourceItem item)
{
this.item = item;
}
-
- public ResourceItem getTextItem()
- {
- return resources.get("1");
- }
-
+
}
15 years, 7 months
Seam SVN: r10413 - trunk/doc/Seam_Reference_Guide/en-US.
by seam-commits@lists.jboss.org
Author: dan.j.allen
Date: 2009-04-14 16:45:29 -0400 (Tue, 14 Apr 2009)
New Revision: 10413
Modified:
trunk/doc/Seam_Reference_Guide/en-US/Getting_Started_With_JBoss_Tools.xml
Log:
fix broken ulink
Modified: trunk/doc/Seam_Reference_Guide/en-US/Getting_Started_With_JBoss_Tools.xml
===================================================================
--- trunk/doc/Seam_Reference_Guide/en-US/Getting_Started_With_JBoss_Tools.xml 2009-04-14 19:03:01 UTC (rev 10412)
+++ trunk/doc/Seam_Reference_Guide/en-US/Getting_Started_With_JBoss_Tools.xml 2009-04-14 20:45:29 UTC (rev 10413)
@@ -36,7 +36,7 @@
<para>
Please see the official <ulink
url="http://www.jboss.org/tools/download/installation">JBoss Tools
- installation</para> page for the quickest way to get JBoss Tools setup
+ installation</ulink> page for the quickest way to get JBoss Tools setup
in Eclipse. You can also check out the <ulink
url="http://www.jboss.org/community/wiki/InstallingJBossTools">Installing
JBoss Tools</ulink> page on the JBoss community wiki for the gory
15 years, 7 months