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.
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@objectweb.org mailing list.
> To unsubscribe: mailto:xwiki-commits-unsubscribe@objectweb.org
> For general help: mailto: sympa@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@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