As I said on the Virtual Office yesterday, first I
commit in trunk,
then after you check the code and say that it's safe, we merge to 1.0.
Right. My bad, I had forgotten :)
BTW I have tested it on trunk and it all worked fine. I tested this:
* Change the password of an existing user both by setting the same
password and a new one. Verified that the export now shows a hashed
password
* Registered a new user. Verified that the export shows a hashed
password
I haven't tried yet scripting the export to see if it fails for non
admin users.
Thanks
-Vincent
On 4/24/07, Vincent Massol <vincent(a)massol.net> wrote:
Should any of these go in RC2 (I didn't see any merge and I'm asking
to be sure we're not forgetting anything)?
Same question for rev 2959 ("Forgot something...", which btw should
have contained a jira reference... ;-))
Thanks
-Vincent
On Apr 23, 2007, at 10:23 PM, Sergiu Dumitriu wrote:
Author: sdumitriu
Date: 2007-04-23 22:23:53 +0200 (Mon, 23 Apr 2007)
New Revision: 2957
Modified:
xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/
PasswordClass.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/
PasswordMetaClass.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/plugin/packaging/
Package.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/user/impl/xwiki/
XWikiAuthServiceImpl.java
Log:
XWIKI-70: password can be searched
XWIKI-580: Implement HASH password mechanism
Added support for hashing passwords. There's some code related to
encrypting passwords, but the actual encrypt/decrypt mechanism is
not written yet.
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/
classes/PasswordClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/
PasswordClass.java 2007-04-23 20:16:46 UTC (rev 2956)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/
PasswordClass.java 2007-04-23 20:23:53 UTC (rev 2957)
@@ -1,70 +1,239 @@
-/*
- * Copyright 2006, XpertNet SARL, and individual contributors as
indicated
- * by the contributors.txt.
- *
- * This 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.
- *
- * This software 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.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- *
- * @author sdumitriu
- */
-
-package com.xpn.xwiki.objects.classes;
-
-import com.xpn.xwiki.XWikiContext;
-import com.xpn.xwiki.objects.BaseCollection ;
-import com.xpn.xwiki.objects.BaseProperty;
-import com.xpn.xwiki.objects.ElementInterface;
-import com.xpn.xwiki.objects.meta.PropertyMetaClass;
-import org.apache.ecs.xhtml.input;
-
-public class PasswordClass extends StringClass {
- public PasswordClass(PropertyMetaClass wclass) {
- super("password", "Password", wclass);
- setxWikiClass(wclass);
- }
-
- public PasswordClass() {
- this(null);
- }
-
- public BaseProperty fromString(String value) {
- if (value.equals("********"))
- return null;
- else
- return super.fromString(value);
- }
-
- public void displayHidden(StringBuffer buffer, String name,
String prefix, BaseCollection object, XWikiContext context) {
- // Passwords cannot go through the preview interface of we
don't do something here..
- }
-
- public void displayView(StringBuffer buffer, String name,
String prefix, BaseCollection object, XWikiContext context) {
- ElementInterface prop = object.safeget(name);
- if (prop!=null)
- buffer.append("********");
- }
-
- public void displayEdit(StringBuffer buffer, String name,
String prefix, BaseCollection object, XWikiContext context) {
- input input = new input();
- ElementInterface prop = object.safeget(name);
- if (prop!=null) input.setValue ("********");
-
- input.setType("password");
- input.setName(prefix + name);
- input.setID(prefix + name);
- input.setSize(getSize());
- buffer.append(input.toString());
- }
-}
\ No newline at end of file
+/*
+ * Copyright 2006, XpertNet SARL, and individual contributors as
indicated
+ * by the contributors.txt.
+ *
+ * This 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.
+ *
+ * This software 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ *
+ * @author sdumitriu
+ */
+
+package com.xpn.xwiki.objects.classes;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException ;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ecs.xhtml.input;
+
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.objects.BaseCollection;
+import com.xpn.xwiki.objects.BaseProperty;
+import com.xpn.xwiki.objects.ElementInterface;
+import com.xpn.xwiki.objects.meta.PasswordMetaClass;
+import com.xpn.xwiki.objects.meta.PropertyMetaClass;
+
+public class PasswordClass extends StringClass
+{
+ protected static Log log = LogFactory.getFactory().getInstance
(PasswordClass.class );
+
+ protected static final String DEFAULT_STORAGE =
PasswordMetaClass.HASH;
+
+ protected static final String DEFAULT_HASH_ALGORITHM =
"SHA-512";
+
+ protected static final String DEFAULT_CRYPT_ALGORITHM = "AES";
+
+ protected static final String HASH_IDENTIFIER = "hash";
+
+ protected static final String CRYPT_IDENTIFIER = "crypt";
+
+ protected static final String SEPARATOR = ":";
+
+ protected static final String FORM_PASSWORD_PLACEHODLER =
"********";
+
+ public PasswordClass(PropertyMetaClass wclass)
+ {
+ super("password", "Password", wclass);
+ setxWikiClass(wclass);
+ }
+
+ public PasswordClass()
+ {
+ this(null);
+ }
+
+ public BaseProperty fromString(String value)
+ {
+ if (value.equals(FORM_PASSWORD_PLACEHODLER)) {
+ return null;
+ }
+ BaseProperty property = newProperty();
+ property.setValue (getProcessedPassword(value));
+ return property;
+ }
+
+ public void displayHidden(StringBuffer buffer, String name,
String prefix,
+ BaseCollection object, XWikiContext context)
+ {
+ // Passwords cannot go through the preview interface, so
we don't do something here..
+ }
+
+ public void displayView(StringBuffer buffer, String name,
String prefix,
+ BaseCollection object, XWikiContext context)
+ {
+ ElementInterface prop = object.safeget(name);
+ if (prop != null) {
+ buffer.append(FORM_PASSWORD_PLACEHODLER);
+ }
+ }
+
+ public void displayEdit(StringBuffer buffer, String name,
String prefix,
+ BaseCollection object, XWikiContext context)
+ {
+ input input = new input();
+ ElementInterface prop = object.safeget(name);
+ if (prop != null) {
+ input.setValue(FORM_PASSWORD_PLACEHODLER);
+ }
+
+ input.setType("password");
+ input.setName(prefix + name);
+ input.setSize(getSize());
+ buffer.append(input.toString());
+ }
+
+ /**
+ *
+ * @return One of 'Clear', 'Hash' or 'Encrypt'.
+ */
+ public String getStorageType()
+ {
+ BaseProperty st = (BaseProperty) this.getField
("storageType");
+ if (st != null) {
+ String type = st.getValue().toString().trim();
+ if (!type.equals("")) {
+ return type;
+ }
+ }
+ return DEFAULT_STORAGE;
+ }
+
+ /**
+ *
+ * @return The hash algorithm configured for this XProperty.
+ */
+ public String getHashAlgorithm()
+ {
+ BaseProperty alg = (BaseProperty) this.getField
(PasswordMetaClass.ALGORITHM_KEY);
+ if (alg != null && alg.getValue() != null && !alg.getValue
().toString().trim().equals("")) {
+ return alg.getValue().toString();
+ }
+ return DEFAULT_HASH_ALGORITHM;
+ }
+
+ /**
+ *
+ * @return The encryption algorithm configured for this
XProperty.
+ */
+ public String getCryptAlgorithm()
+ {
+ BaseProperty alg = (BaseProperty) this.getField
(PasswordMetaClass.ALGORITHM_KEY);
+ if (alg != null && alg.getValue() != null && !alg.getValue
().toString().trim().equals("")) {
+ return alg.getValue().toString();
+ }
+ return DEFAULT_CRYPT_ALGORITHM;
+ }
+
+ /**
+ *
+ * @param password
+ * @return The algorithm used for the given password.
+ */
+ public String getAlgorithmFromPassword(String password)
+ {
+ int beginIndex = password.indexOf(SEPARATOR) + 1;
+ if (beginIndex >= 0) {
+ int endIndex = password.indexOf(SEPARATOR, beginIndex);
+ if (endIndex >= 0) {
+ return password.substring(beginIndex, endIndex);
+ }
+ }
+ return DEFAULT_HASH_ALGORITHM;
+ }
+
+ /**
+ * Transforms a plain text password so that it has the same
encryption as a password stored in
+ * the database. The current configuration for this password
XProperty cannot be used, as the
+ * user might have a different encryption mechanism (for
example, if the user was imported, or
+ * the password was not yet upgraded).
+ *
+ * @param storedPassword The stored password, which gives the
storage type and algorithm.
+ * @param plainPassword The plain text password to be
encrypted.
+ * @return The input password, encrypted
with the same
mechanism as the stored password.
+ */
+ public String getEquivalentPassword(String storedPassword,
String plainPassword)
+ {
+ String result = plainPassword;
+ if (storedPassword.startsWith(HASH_IDENTIFIER +
SEPARATOR)) {
+ result = getPasswordHash(result,
getAlgorithmFromPassword(storedPassword));
+ } else if (storedPassword.startsWith (CRYPT_IDENTIFIER +
SEPARATOR)) {
+ result = getPasswordCrypt(result,
getAlgorithmFromPassword(storedPassword));
+ }
+ return result;
+ }
+
+ public String getProcessedPassword(String password)
+ {
+ String storageType = getStorageType();
+ String result = password;
+ if (storageType.equals(PasswordMetaClass.HASH )) {
+ result = getPasswordHash(result);
+ } else if (storageType.equals
(PasswordMetaClass.ENCRYPTED)) {
+ result = getPasswordCrypt(result);
+ }
+ return result;
+ }
+
+ public String getPasswordCrypt(String password)
+ {
+ return getPasswordCrypt(password, getCryptAlgorithm());
+ }
+
+ public String getPasswordCrypt(String password, String
algorithmName)
+ {
+ // TODO Write me!
+ return password;
+ }
+
+ public String getPasswordHash(String password)
+ {
+ return getPasswordHash(password, getHashAlgorithm());
+ }
+
+ public String getPasswordHash(String password, String
algorithmName)
+ {
+ try {
+ MessageDigest hashAlgorithm = MessageDigest.getInstance
(algorithmName);
+ hashAlgorithm.update(password.getBytes());
+ byte[] digest = hashAlgorithm.digest();
+ StringBuffer sb =
+ new StringBuffer(HASH_IDENTIFIER + SEPARATOR +
algorithmName + SEPARATOR);
+ for (int j = 0; j < digest.length; ++j) {
+ int b = digest[j] & 0xFF;
+ if (b < 0x10)
+ sb.append('0');
+ sb.append(Integer.toHexString(b));
+ }
+ return sb.toString();
+ } catch (NoSuchAlgorithmException ex) {
+ log.error("Wrong hash algorithm '" + algorithmName +
"' in '" + this.className + "'",
+ ex);
+ } catch (NullPointerException ex) {
+ log.error("Error hashing password", ex);
+ }
+ return password;
+ }
+}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/
PasswordMetaClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/
PasswordMetaClass.java 2007-04-23 20:16:46 UTC (rev 2956)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/
PasswordMetaClass.java 2007-04-23 20:23:53 UTC (rev 2957)
@@ -1,5 +1,5 @@
/*
- * Copyright 2006, XpertNet SARL, and individual contributors as
indicated
+ * Copyright 2006-2007, XpertNet SARL, and individual contributors
as indicated
* by the contributors.txt.
*
* This is free software; you can redistribute it and/or modify it
@@ -17,7 +17,6 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA
* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
*
- * @author ludovic
*/
package com.xpn.xwiki.objects.meta;
@@ -25,17 +24,46 @@
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.objects.BaseCollection;
import com.xpn.xwiki.objects.classes.PasswordClass;
+import com.xpn.xwiki.objects.classes.StaticListClass;
+import com.xpn.xwiki.objects.classes.StringClass;
-public class PasswordMetaClass extends StringMetaClass {
+public class PasswordMetaClass extends StringMetaClass
+{
+ public static final String CLEAR = "Clear";
- public PasswordMetaClass() {
+ public static final String ENCRYPTED = "Encrypted";
+
+ public static final String HASH = "Hash";
+
+ public static final String SEPARATOR = "|";
+
+ public static final String ALGORITHM_KEY = "algorithm";
+
+ public PasswordMetaClass()
+ {
super();
- // setType("passwordmetaclass");
setPrettyName("Password Class");
setName( PasswordClass.class.getName());
+
+ StaticListClass storageType_class = new StaticListClass
(this);
+ storageType_class.setName("storageType");
+ storageType_class.setPrettyName("Storage type");
+ storageType_class.setValues(CLEAR + SEPARATOR + HASH);// +
SEPARATOR + ENCRYPTED
+ storageType_class.setRelationalStorage(false);
+ storageType_class.setDisplayType("select");
+ storageType_class.setMultiSelect(false);
+ storageType_class.setSize(1);
+ safeput("storageType", storageType_class);
+
+ StringClass encryptAlgorithm_class = new StringClass(this);
+ encryptAlgorithm_class.setName(ALGORITHM_KEY);
+ encryptAlgorithm_class.setPrettyName("Encryption/hash
algorithm");
+ encryptAlgorithm_class.setSize(20);
+ safeput("encryptAlgorithm", encryptAlgorithm_class);
}
- public BaseCollection newObject(XWikiContext context) {
+ public BaseCollection newObject(XWikiContext context)
+ {
return new PasswordClass();
}
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/plugin/
packaging/Package.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/plugin/packaging/
Package.java 2007-04-23 20:16:46 UTC (rev 2956)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/plugin/packaging/
Package.java 2007-04-23 20:23:53 UTC (rev 2957)
@@ -755,6 +755,12 @@
ZipEntry zipentry = new ZipEntry(zipname);
zos.putNextEntry(zipentry);
String docXml = doc.toXML (true, false, true,
withVersions, context);
+ if (!context.getWiki().getRightService().hasAdminRights
(context)) {
+ docXml =
+ context.getUtil ().substitute(
+ "s/<password>.*?<\\/password>/
<password>********<\\/password>/goi",
+ docXml);
+ }
zos.write(docXml.getBytes(context.getWiki().getEncoding
()));
zos.closeEntry();
} catch (Exception e) {
@@ -786,6 +792,12 @@
}
File file = new File(spacedir, filename);
String xml = doc.toXML(true, false, true,
withVersions, context);
+ if (!context.getWiki().getRightService().hasAdminRights
(context)) {
+ xml =
+ context.getUtil().substitute(
+ "s/<password>.*?<\\/password>/
<password>********<\\/password>/goi",
+ xml);
+ }
FileOutputStream fos = new FileOutputStream(file);
fos.write(xml.getBytes(context.getWiki().getEncoding
()));
fos.flush();
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/user/impl/
xwiki/XWikiAuthServiceImpl.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/user/impl/xwiki/
XWikiAuthServiceImpl.java 2007-04-23 20:16:46 UTC (rev 2956)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/user/impl/xwiki/
XWikiAuthServiceImpl.java 2007-04-23 20:23:53 UTC (rev 2957)
@@ -22,27 +22,30 @@
package com.xpn.xwiki.user.impl.xwiki;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.securityfilter.config.SecurityConfig;
+import org.securityfilter.filter.SecurityRequestWrapper;
+import org.securityfilter.realm.SimplePrincipal;
+
import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.objects.classes.PasswordClass ;
import com.xpn.xwiki.plugin.ldap.LDAPPlugin;
-import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.user.api.XWikiAuthService;
import com.xpn.xwiki.user.api.XWikiUser;
import com.xpn.xwiki.web.Utils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.securityfilter.config.SecurityConfig ;
-import org.securityfilter.filter.SecurityRequestWrapper;
-import org.securityfilter.realm.SimplePrincipal;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse ;
-import java.io.IOException;
-import java.security.Principal;
-import java.util.List;
-
public class XWikiAuthServiceImpl implements XWikiAuthService
{
private static final Log log = LogFactory.getLog
(XWikiAuthServiceImpl.class);
@@ -390,6 +393,10 @@
// We only allow empty password from users having a
XWikiUsers object.
if (doc.getObject ("XWiki.XWikiUsers") != null) {
String passwd = doc.getStringValue
("XWiki.XWikiUsers", "password");
+ password =
+ ((PasswordClass) context.getWiki().getClass
("XWiki.XWikiUsers", context)
+ .getField
("password")).getEquivalentPassword(passwd, password);
+
result = ( password.equals(passwd));
}
--
You receive this message as a subscriber of the xwiki-
commits(a)objectweb.org mailing list.
To unsubscribe: mailto:xwiki-commits-unsubscribe@objectweb.org
For general help: mailto: sympa(a)objectweb.org?subject=help
ObjectWeb mailing lists service home page:
http://www.objectweb.org/
wws
--
You receive this message as a subscriber of the xwiki-
dev(a)objectweb.org mailing list.
To unsubscribe: mailto:xwiki-dev-unsubscribe@objectweb.org
For general help: mailto: sympa(a)objectweb.org?subject=help
ObjectWeb mailing lists service home page:
http://www.objectweb.org/
wws
--
http://purl.org/net/sergiu
--
You receive this message as a subscriber of the xwiki-
dev(a)objectweb.org mailing list.
To unsubscribe: mailto:xwiki-dev-unsubscribe@objectweb.org
For general help: mailto:sympa@objectweb.org?subject=help
ObjectWeb mailing lists service home page:
http://www.objectweb.org/
wws