You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2010/03/03 12:13:28 UTC

svn commit: r918412 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/security/authentication/ main/java/org/apache/jackrabbit/core/security/user/ test/java/org/apache/jackrabbit/api/security/user/ test/java/org/apache/ja...

Author: angela
Date: Wed Mar  3 11:13:27 2010
New Revision: 918412

URL: http://svn.apache.org/viewvc?rev=918412&view=rev
Log:
- JCR-2527: Fix and simplify CryptedSimpleCredentials
- minor improvements: comments, @Override annotation, redundant throws clause
- consistently use AbstractUserTest#buildPassword(String) for simple user creation

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerCreateUserTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentialsTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java Wed Mar  3 11:13:27 2010
@@ -18,11 +18,14 @@
 
 import org.apache.jackrabbit.core.security.SecurityConstants;
 import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.jcr.Credentials;
 import javax.jcr.SimpleCredentials;
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
+import java.security.MessageDigest;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -32,14 +35,18 @@
  */
 public class CryptedSimpleCredentials implements Credentials {
 
+    private static final Logger log = LoggerFactory.getLogger(CryptedSimpleCredentials.class);
+
     private final String algorithm;
     private final String cryptedPassword;
     private final String userId;
     private final Map<String, Object> attributes;
 
     /**
-     * Take {@link javax.jcr.SimpleCredentials SimpleCredentials} and
-     * digest the password if it is plain-text
+     * Build a new instance of <code>CryptedSimpleCredentials</code> from the
+     * given {@link javax.jcr.SimpleCredentials SimpleCredentials} and create
+     * the crypted password field using the {@link SecurityConstants#DEFAULT_DIGEST
+     * default digest}.
      *
      * @param credentials
      * @throws NoSuchAlgorithmException
@@ -56,16 +63,8 @@
             throw new IllegalArgumentException();
         }
         String password = new String(pwd);
-        String algo =  getAlgorithm(password);
-        if (algo == null) {
-            // password is plain text
-            algorithm = SecurityConstants.DEFAULT_DIGEST;
-            cryptedPassword = crypt(password, algorithm);
-        } else {
-            // password is already encrypted
-            algorithm = algo;
-            cryptedPassword = password;
-        }
+        algorithm = SecurityConstants.DEFAULT_DIGEST;
+        cryptedPassword = crypt(password, algorithm);
 
         String[] attNames = credentials.getAttributeNames();
         attributes = new HashMap<String, Object>(attNames.length);
@@ -74,20 +73,39 @@
         }
     }
 
-    public CryptedSimpleCredentials(String userId, String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
-        if (userId == null || userId.length() == 0 || password == null) {
-            throw new IllegalArgumentException("Invalid userID or password. Neither may be null, the userID must have a length > 0.");
+    /**
+     * Create a new instanceof <code>CryptedSimpleCredentials</code> from the
+     * given <code>userId</code> and <code>cryptedPassword</code> strings.
+     * In contrast to {@link CryptedSimpleCredentials(SimpleCredentials)} that
+     * expects the password to be plain text this constructor expects the
+     * password to be already crypted. However, it performs a simple validation
+     * and calls {@link Text#digest(String, byte[])} using the
+     * {@link SecurityConstants#DEFAULT_DIGEST default digest} in case the
+     * given password is found to be plain text.
+     *
+     * @param userId
+     * @param cryptedPassword
+     * @throws NoSuchAlgorithmException
+     * @throws UnsupportedEncodingException
+     */
+    public CryptedSimpleCredentials(String userId, String cryptedPassword) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+        if (userId == null || userId.length() == 0) {
+            throw new IllegalArgumentException("Invalid userID: The userID must have a length > 0.");
+        }
+        if (cryptedPassword == null) {
+            throw new IllegalArgumentException("Password may not be null.");
         }
         this.userId = userId;
-        String algo =  getAlgorithm(password);
+        String algo =  extractAlgorithm(cryptedPassword);
         if (algo == null) {
-            // password is plain text
+            // password is plain text including those starting with {invalidAlgorithm}
+            log.debug("Plain text password -> Using " + SecurityConstants.DEFAULT_DIGEST + " to create digest.");
             algorithm = SecurityConstants.DEFAULT_DIGEST;
-            cryptedPassword = crypt(password, algorithm);
+            this.cryptedPassword = crypt(cryptedPassword, algorithm);
         } else {
-            // password is already encrypted
+            // password is already encrypted and started with {validAlgorithm}
             algorithm = algo;
-            cryptedPassword = password;
+            this.cryptedPassword = cryptedPassword;
         }
         attributes = Collections.emptyMap();
     }
@@ -114,9 +132,18 @@
 
     /**
      * Compares this instance with the given <code>SimpleCredentials</code> and
-     * returns <code>true</code> if both match.
+     * returns <code>true</code> if both match. Successful match is defined to
+     * be the result of
+     * <ul>
+     * <li>Case-insensitive comparison of the UserIDs</li>
+     * <li>Equality of the passwords if the password contained in the simple
+     * credentials is hashed with the algorithm defined in this credentials object.</li>
+     * </ul>
      *
-     * @param credentials
+     * NOTE, that the simple credentials are exptected to contain the plain text
+     * password.
+     *
+     * @param credentials An instance of simple credentials.
      * @return true if {@link SimpleCredentials#getUserID() UserID} and
      * {@link SimpleCredentials#getPassword() Password} match.
      * @throws NoSuchAlgorithmException
@@ -126,24 +153,20 @@
             throws NoSuchAlgorithmException, UnsupportedEncodingException {
 
         if (getUserID().equalsIgnoreCase(credentials.getUserID())) {
-            String toMatch = new String(credentials.getPassword());
-            String algr = getAlgorithm(toMatch);
-
-            if (algr == null && algorithm != null) {
-                // pw to match not crypted -> crypt with algorithm present here.
-                return crypt(toMatch, algorithm).equals(cryptedPassword);
-            } else if (algr != null && algorithm == null) {
-                // crypted pw to match but unknown algorithm here -> crypt this pw
-                return crypt(algr, cryptedPassword).equals(toMatch);
-            }
-
-            // both pw to compare define a algorithm and are crypted
-            // -> simple comparison of the 2 password strings.
-            return toMatch.equals(cryptedPassword);
+            // crypt the password retrieved from the given simple credentials
+            // and test if it is equal to the cryptedPassword field.
+            return cryptedPassword.equals(crypt(String.valueOf(credentials.getPassword()), algorithm));
         }
         return false;
     }
 
+    /**
+     * @param pwd Plain text password
+     * @param algorithm The algorithm to be used for the digest.
+     * @return Digest of the given password with leading algorithm information.
+     * @throws NoSuchAlgorithmException
+     * @throws UnsupportedEncodingException
+     */
     private static String crypt(String pwd, String algorithm)
             throws NoSuchAlgorithmException, UnsupportedEncodingException {
 
@@ -153,12 +176,30 @@
         return password.toString();
     }
 
-    private static String getAlgorithm(String password) {
-        int end = password.indexOf("}");
-        if (password.startsWith("{") && end > 0) {
-            return password.substring(1, end);
-        } else {
-            return null;
+    /**
+     * Extract the algorithm from the given crypted password string. Returns the
+     * algorithm or <code>null</code> if the given string doesn't have a
+     * leading <code>{algorith}</code> such as created by {@link #crypt(String, String)
+     * or if the extracted string doesn't represent an available algorithm.
+     *
+     * @param cryptedPwd
+     * @return The algorithm or <code>null</code> if the given string doesn't have a
+     * leading <code>{algorith}</code> such as created by {@link #crypt(String, String)
+     * or if the extracted string isn't an available algorithm. 
+     */
+    private static String extractAlgorithm(String cryptedPwd) {
+        int end = cryptedPwd.indexOf("}");
+        if (cryptedPwd.startsWith("{") && end > 0) {
+            String algorithm = cryptedPwd.substring(1, end);
+            try {
+                MessageDigest.getInstance(algorithm);
+                return algorithm;
+            } catch (NoSuchAlgorithmException e) {
+                log.debug("Invalid algorithm detected " + algorithm);
+            }
         }
+
+        // not starting with {} or invalid algorithm
+        return null;
     }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java Wed Mar  3 11:13:27 2010
@@ -155,7 +155,8 @@
         checkProtectedProperty(name);
         try {
             // check if the property has already been created as multi valued
-            // property before -> in this case remove in order to avoid valueformatex.
+            // property before -> in this case remove in order to avoid
+            // ValueFormatException.
             if (node.hasProperty(name)) {
                 Property p = node.getProperty(name);
                 if (p.isMultiple()) {
@@ -188,7 +189,8 @@
         checkProtectedProperty(name);
         try {
             // check if the property has already been created as single valued
-            // property before -> in this case remove in order to avoid valueformatex.
+            // property before -> in this case remove in order to avoid
+            // ValueFormatException.
             if (node.hasProperty(name)) {
                 Property p = node.getProperty(name);
                 if (!p.isMultiple()) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java Wed Mar  3 11:13:27 2010
@@ -131,6 +131,7 @@
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlProvider#init(Session, Map)
      */
+    @Override
     public void init(Session systemSession, Map configuration) throws RepositoryException {
         super.init(systemSession, configuration);
         if (systemSession instanceof SessionImpl) {
@@ -321,6 +322,7 @@
         /**
          * @see AbstractCompiledPermissions#buildResult(Path)
          */
+        @Override
         protected Result buildResult(Path path) throws RepositoryException {
             NodeImpl userNode = null;
             try {
@@ -375,7 +377,8 @@
                     }
                 } else {
                     // rep:User node or some other custom node below an existing user.
-                    // as the auth-folder doesn't allow other residual child nodes.
+                    // as the authorizable folder doesn't allow other residual
+                    // child nodes.
                     boolean editingOwnUser = node.isSame(userNode);
                     if (editingOwnUser) {
                         // user can only read && write his own props
@@ -426,6 +429,7 @@
         /**
          * @see CompiledPermissions#close()
          */
+        @Override
         public void close() {
             try {
                 observationMgr.removeEventListener(this);
@@ -438,6 +442,7 @@
         /**
          * @see CompiledPermissions#grants(Path, int)
          */
+        @Override
         public boolean grants(Path absPath, int permissions) throws RepositoryException {
             if (permissions == Permission.READ) {
                 // read is always granted
@@ -450,6 +455,7 @@
         /**
          * @see CompiledPermissions#canReadAll()
          */
+        @Override
         public boolean canReadAll() throws RepositoryException {
             return true;
         }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java Wed Mar  3 11:13:27 2010
@@ -44,15 +44,15 @@
 
     //--------------------------------------------------------------------------
     /**
-     *
+     * Creates a hash of the specified password if it is found to be plain text.
+     * 
      * @param password
      * @return
      * @throws RepositoryException
      */
     static String buildPasswordValue(String password) throws RepositoryException {
         try {
-            CryptedSimpleCredentials creds = new CryptedSimpleCredentials("_", password);
-            return creds.getPassword();
+            return new CryptedSimpleCredentials("_", password).getPassword();
         } catch (NoSuchAlgorithmException e) {
             throw new RepositoryException(e);
         } catch (UnsupportedEncodingException e) {
@@ -122,9 +122,6 @@
      * @see User#changePassword(String)
      */
     public void changePassword(String password) throws RepositoryException {
-        if (password == null) {
-            throw new IllegalArgumentException("The password may never be null.");
-        }
         Value v = getSession().getValueFactory().createValue(buildPasswordValue(password));
         userManager.setProtectedProperty(getNode(), P_PASSWORD, v);
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java Wed Mar  3 11:13:27 2010
@@ -244,7 +244,7 @@
      * @param adminId The user ID of the administrator.
      * @throws RepositoryException If an error occurs.
      */
-    public UserManagerImpl(SessionImpl session, String adminId) throws RepositoryException {
+    public UserManagerImpl(SessionImpl session, String adminId) {
         this(session, adminId, null);
     }
 
@@ -267,7 +267,7 @@
      * @param config The configuration parameters.
      * @throws RepositoryException If an error occurs.
      */
-    public UserManagerImpl(SessionImpl session, String adminId, Properties config) throws RepositoryException {
+    public UserManagerImpl(SessionImpl session, String adminId, Properties config) {
         this.session = session;
         this.adminId = adminId;
 
@@ -657,7 +657,7 @@
                 if (n == null) {
                     // no user -> look for group.
                     // NOTE: JR < 2.0 always returned groupIDs that didn't contain any
-                    // illegal JCR chars. Since Group.getID() now unescapes the node
+                    // illegal JCR chars. Since Group.getID() 'unescapes' the node
                     // name additional escaping is required.
                     Name nodeName = session.getQName(Text.escapeIllegalJcrChars(id));
                     n = (NodeImpl) authResolver.findNode(nodeName, NT_REP_GROUP);
@@ -668,7 +668,7 @@
         return getAuthorizable(n);
     }
 
-    private Value getValue(String strValue) throws RepositoryException {
+    private Value getValue(String strValue) {
         return session.getValueFactory().createValue(strValue);
     }
 
@@ -757,9 +757,7 @@
      * process.</li>
      * </ul>
      *
-     * @param adminId
-     * @param pw
-     * @return
+     * @return The admin user.
      * @throws RepositoryException
      */
     private User createAdmin() throws RepositoryException {

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java Wed Mar  3 11:13:27 2010
@@ -115,6 +115,10 @@
         }
     }
 
+    protected String buildPassword(String uid) {
+        return buildPassword(uid, false);
+    }
+
     protected String buildPassword(Principal p) {
         return buildPassword(p.getName(), false);
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerCreateUserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerCreateUserTest.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerCreateUserTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserManagerCreateUserTest.java Wed Mar  3 11:13:27 2010
@@ -32,7 +32,7 @@
 
     private static Logger log = LoggerFactory.getLogger(UserManagerCreateUserTest.class);
 
-    private List<Authorizable> createdUsers = new ArrayList();
+    private List<Authorizable> createdUsers = new ArrayList<Authorizable>();
 
     @Override
     protected void tearDown() throws Exception {
@@ -64,7 +64,7 @@
     public void testCreateUser() throws RepositoryException, NotExecutableException {
         Principal p = getTestPrincipal();
         String uid = p.getName();
-        User user = createUser(uid, buildPassword(uid, false));
+        User user = createUser(uid, buildPassword(uid));
         createdUsers.add(user);
 
         assertNotNull(user.getID());
@@ -74,7 +74,7 @@
     public void testCreateUserWithPath() throws RepositoryException, NotExecutableException {
         Principal p = getTestPrincipal();
         String uid = p.getName();
-        User user = createUser(uid, buildPassword(uid, true), p, "/any/path/to/the/new/user");
+        User user = createUser(uid, buildPassword(uid), p, "/any/path/to/the/new/user");
         createdUsers.add(user);
 
         assertNotNull(user.getID());
@@ -84,7 +84,7 @@
     public void testCreateUserWithPath2() throws RepositoryException, NotExecutableException {
         Principal p = getTestPrincipal();
         String uid = p.getName();
-        User user = createUser(uid, buildPassword(uid, true), p, "any/path");
+        User user = createUser(uid, buildPassword(uid), p, "any/path");
         createdUsers.add(user);
 
         assertNotNull(user.getID());
@@ -94,7 +94,7 @@
     public void testCreateUserWithDifferentPrincipalName() throws RepositoryException, NotExecutableException {
         Principal p = getTestPrincipal();
         String uid = getTestPrincipal().getName();
-        User user = createUser(uid, buildPassword(uid, true), p, "/any/path/to/the/new/user");
+        User user = createUser(uid, buildPassword(uid), p, "/any/path/to/the/new/user");
         createdUsers.add(user);
 
         assertNotNull(user.getID());
@@ -173,7 +173,7 @@
         try {
             Principal p = getTestPrincipal();
             String uid = p.getName();
-            User user = createUser(uid, buildPassword(uid, true), null, "/a/b/c");
+            User user = createUser(uid, buildPassword(uid), null, "/a/b/c");
             createdUsers.add(user);
 
             fail("A User cannot be built with 'null' Principal");
@@ -186,7 +186,7 @@
         try {
             Principal p = getTestPrincipal("");
             String uid = p.getName();
-            User user = createUser(uid, buildPassword(uid, true), p, "/a/b/c");
+            User user = createUser(uid, buildPassword(uid), p, "/a/b/c");
             createdUsers.add(user);
 
             fail("A User cannot be built with ''-named Principal");
@@ -196,7 +196,7 @@
         try {
             Principal p = getTestPrincipal(null);
             String uid = p.getName();
-            User user = createUser(uid, buildPassword(uid, true), p, "/a/b/c");
+            User user = createUser(uid, buildPassword(uid), p, "/a/b/c");
             createdUsers.add(user);
 
             fail("A User cannot be built with ''-named Principal");
@@ -207,11 +207,11 @@
 
     public void testCreateTwiceWithSameUserID() throws RepositoryException, NotExecutableException {
         String uid = getTestPrincipal().getName();
-        User user = createUser(uid, buildPassword(uid, false));
+        User user = createUser(uid, buildPassword(uid));
         createdUsers.add(user);
 
         try {
-            User user2 = createUser(uid, buildPassword("anyPW", true));
+            User user2 = createUser(uid, buildPassword("anyPW"));
             createdUsers.add(user2);
 
             fail("Creating 2 users with the same UserID should throw AuthorizableExistsException.");
@@ -223,12 +223,12 @@
     public void testCreateTwiceWithSamePrincipal() throws RepositoryException, NotExecutableException {
         Principal p = getTestPrincipal();
         String uid = p.getName();
-        User user = createUser(uid, buildPassword(uid, true), p, "a/b/c");
+        User user = createUser(uid, buildPassword(uid), p, "a/b/c");
         createdUsers.add(user);
 
         try {
             uid = getTestPrincipal().getName();
-            User user2 = createUser(uid, buildPassword(uid, false), p, null);
+            User user2 = createUser(uid, buildPassword(uid), p, null);
             createdUsers.add(user2);
 
             fail("Creating 2 users with the same Principal should throw AuthorizableExistsException.");
@@ -241,7 +241,7 @@
         Principal p = getTestPrincipal();
         String uid = p.getName();
 
-        User user = createUser(uid, buildPassword(uid, false));
+        User user = createUser(uid, buildPassword(uid));
         createdUsers.add(user);
 
         assertNotNull(userMgr.getAuthorizable(user.getID()));
@@ -264,7 +264,7 @@
         Principal p = getTestPrincipal();
         String uid = p.getName();
 
-        User user = userMgr.createUser(uid, buildPassword(uid, false));
+        User user = userMgr.createUser(uid, buildPassword(uid));
         superuser.refresh(false);
 
         if (!autosave) {

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentialsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentialsTest.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentialsTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentialsTest.java Wed Mar  3 11:13:27 2010
@@ -16,51 +16,125 @@
  */
 package org.apache.jackrabbit.core.security.authentication;
 
-import org.apache.jackrabbit.api.JackrabbitSession;
-import org.apache.jackrabbit.api.security.user.User;
-import org.apache.jackrabbit.api.security.user.UserManager;
-import org.apache.jackrabbit.test.AbstractJCRTest;
-import org.apache.jackrabbit.test.NotExecutableException;
-
-import javax.jcr.Credentials;
 import javax.jcr.SimpleCredentials;
+import java.security.NoSuchAlgorithmException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+import org.apache.jackrabbit.util.Text;
 
 /**
  * <code>CryptedSimpleCredentialsTest</code>...
  */
-public class CryptedSimpleCredentialsTest extends AbstractJCRTest {
+public class CryptedSimpleCredentialsTest extends TestCase {
 
-    private String userID;
-    private CryptedSimpleCredentials creds;
+    private final String userID = "anyUserID";
+    private final String pw = "somePw";
+
+    private SimpleCredentials sCreds;
+    private List<CryptedSimpleCredentials> cCreds = new ArrayList<CryptedSimpleCredentials>();
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
-        userID = superuser.getUserID();
-        if (superuser instanceof JackrabbitSession) {
-            UserManager umg = ((JackrabbitSession) superuser).getUserManager();
-            User u = (User) umg.getAuthorizable(userID);
-            Credentials crd = u.getCredentials();
-            if (crd instanceof SimpleCredentials) {
-                creds = new CryptedSimpleCredentials((SimpleCredentials) crd);
-            } else {
-                throw new NotExecutableException();
-            }
-        } else {
-            throw new NotExecutableException();
+        sCreds = new SimpleCredentials(userID, pw.toCharArray());
+        // build crypted credentials from the simple credentials
+        CryptedSimpleCredentials cc = new CryptedSimpleCredentials(sCreds);
+        cCreds.add(cc);
+        // build from uid/pw
+        cCreds.add(new CryptedSimpleCredentials(userID, pw));
+        // build from uid and crypted pw
+        cCreds.add(new CryptedSimpleCredentials(userID, cc.getPassword()));
+    }
+
+    public void testSimpleMatch() throws NoSuchAlgorithmException, UnsupportedEncodingException {
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertTrue(cc.matches(sCreds));
         }
     }
 
     public void testUserIDMatchesCaseInsensitive() throws Exception {
         String uid = userID.toUpperCase();
-        assertTrue(creds.matches(new SimpleCredentials(uid, creds.getPassword().toCharArray())));
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertTrue(cc.matches(new SimpleCredentials(uid, pw.toCharArray())));
+        }
 
         uid = userID.toLowerCase();
-        assertTrue(creds.matches(new SimpleCredentials(uid, creds.getPassword().toCharArray())));
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertTrue(cc.matches(new SimpleCredentials(uid, pw.toCharArray())));
+        }
     }
 
     public void testGetUserID() {
-        assertEquals(userID, creds.getUserID());
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertEquals(userID, cc.getUserID());
+        }
+    }
+
+    public void testGetPassword() throws NoSuchAlgorithmException, UnsupportedEncodingException {
+        CryptedSimpleCredentials prev = null;
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertFalse(pw.equals(cc.getPassword()));
+            if (prev != null) {
+                assertEquals(prev.getPassword(), cc.getPassword());
+            }
+            prev = cc;
+        }
+
+        // build crypted credentials from the uid and the crypted pw contained
+        // in simple credentials -> simple-c-password must be treated plain-text
+        SimpleCredentials sc = new SimpleCredentials(userID, prev.getPassword().toCharArray());
+        CryptedSimpleCredentials diff = new CryptedSimpleCredentials(sc);
+
+        assertFalse(prev.getPassword().equals(diff.getPassword()));
+        assertFalse(String.valueOf(sc.getPassword()).equals(diff.getPassword()));
+    }
+
+    public void testGetAlgorithm() {
+        CryptedSimpleCredentials prev = null;
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertNotNull(cc.getAlgorithm());
+            if (prev != null) {
+                assertEquals(prev.getAlgorithm(), cc.getAlgorithm());
+            }
+            prev = cc;
+        }
+    }
+
+    public void testPasswordMatch() throws NoSuchAlgorithmException, UnsupportedEncodingException {
+        // simple credentials containing the crypted pw must not match.
+        SimpleCredentials sc = new SimpleCredentials(userID, cCreds.get(0).getPassword().toCharArray());
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertFalse(cc.matches(sc));
+        }
+
+        // simple credentials containing different pw must not match.
+        SimpleCredentials sc2 = new SimpleCredentials(userID, "otherPw".toCharArray());
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertFalse(cc.matches(sc2));
+        }
+
+        // simple credentials with pw in digested form must not match.
+        SimpleCredentials sc3 = new SimpleCredentials(userID, "{unknown}somePw".toCharArray());
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertFalse(cc.matches(sc3));
+        }
+
+        // simple credentials with pw with different digest must not match
+        SimpleCredentials sc4 = new SimpleCredentials(userID, ("{md5}"+Text.digest("md5", pw.getBytes("UTF-8"))).toCharArray());
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertFalse(cc.matches(sc4));
+        }
+    }
+
+    public void testUserIdMatch()  throws NoSuchAlgorithmException, UnsupportedEncodingException {
+        // simple credentials containing a different uid must not match
+        SimpleCredentials sc = new SimpleCredentials("another", pw.toCharArray());
+        for (CryptedSimpleCredentials cc : cCreds) {
+            assertFalse(cc.matches(sc));
+        }
     }
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java Wed Mar  3 11:13:27 2010
@@ -46,9 +46,10 @@
  */
 public class AuthorizableImplTest extends AbstractUserTest {
 
-    private List<String> protectedUserProps = new ArrayList();
-    private List<String> protectedGroupProps = new ArrayList();
+    private List<String> protectedUserProps = new ArrayList<String>();
+    private List<String> protectedGroupProps = new ArrayList<String>();
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
 
@@ -313,7 +314,7 @@
 
         assertEquals(user, user2);
         assertEquals(user.hashCode(), user2.hashCode());
-        Set<Authorizable> s = new HashSet();
+        Set<Authorizable> s = new HashSet<Authorizable>();
         s.add(user);
         assertFalse(s.add(user2));
 

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java Wed Mar  3 11:13:27 2010
@@ -20,11 +20,11 @@
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.core.security.SecurityConstants;
 import org.apache.jackrabbit.core.security.authentication.CryptedSimpleCredentials;
 import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.value.StringValue;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import javax.jcr.Credentials;
 import javax.jcr.RepositoryException;
@@ -34,19 +34,20 @@
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * <code>UserImplTest</code>...
  */
 public class UserImplTest extends AbstractUserTest {
 
-    private static Logger log = LoggerFactory.getLogger(UserImplTest.class);
-
     private String uID;
     private Credentials creds;
     private Session uSession;
     private UserManager uMgr;
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
 
@@ -62,6 +63,7 @@
         uMgr = getUserManager(uSession);
     }
 
+    @Override
     protected void tearDown() throws Exception {
         try {
             userMgr.getAuthorizable(uID).remove();
@@ -120,23 +122,64 @@
         assertNull(u.getProperty(propertyName1));
     }
 
+    public void testCredentials() throws RepositoryException, NoSuchAlgorithmException, UnsupportedEncodingException {
+        User u = (User) userMgr.getAuthorizable(uID);
+
+        Credentials uc = u.getCredentials();
+        assertTrue(uc instanceof CryptedSimpleCredentials);
+        assertTrue(((CryptedSimpleCredentials) uc).matches((SimpleCredentials) creds));
+    }
+
     public void testChangePassword() throws RepositoryException, NotExecutableException, NoSuchAlgorithmException, UnsupportedEncodingException {
-        String oldPw = getHelper().getProperty("javax.jcr.tck.superuser.pwd");
-        if (oldPw == null) {
-            // missing property
-            throw new NotExecutableException();
+        User u = (User) userMgr.getAuthorizable(uID);
+
+        String sha1Hash = "{" +SecurityConstants.DEFAULT_DIGEST+ "}" + Text.digest(SecurityConstants.DEFAULT_DIGEST, "abc".getBytes());
+        String md5Hash = "{md5}" + Text.digest("md5", "abc".getBytes());
+
+        // valid passwords and the corresponding match
+        Map<String,String> pwds = new HashMap<String, String>();
+        // plain text passwords
+        pwds.put("abc", "abc");
+        pwds.put("{a}password", "{a}password");
+        // passwords already in hashed format.
+        pwds.put(sha1Hash, "abc");
+        pwds.put(md5Hash, "abc");
+
+        for (String pw : pwds.keySet()) {
+            u.changePassword(pw);
+
+            String plain = pwds.get(pw);
+            SimpleCredentials sc = new SimpleCredentials(u.getID(), plain.toCharArray());
+            CryptedSimpleCredentials cc = (CryptedSimpleCredentials) u.getCredentials();
+
+            assertTrue(cc.matches(sc));
         }
 
-        User user = getTestUser(superuser);
-        try {
-            user.changePassword("pw");
-            save(superuser);
+        // valid passwords, non-matching plain text
+        Map<String, String>noMatch = new HashMap<String, String>();
+        noMatch.put("{"+SecurityConstants.DEFAULT_DIGEST+"}", "");
+        noMatch.put("{"+SecurityConstants.DEFAULT_DIGEST+"}", "{"+SecurityConstants.DEFAULT_DIGEST+"}");
+        noMatch.put("{"+SecurityConstants.DEFAULT_DIGEST+"}any", "any");
+        noMatch.put("{"+SecurityConstants.DEFAULT_DIGEST+"}any", "{"+SecurityConstants.DEFAULT_DIGEST+"}any");
+        noMatch.put(sha1Hash, sha1Hash);
+        noMatch.put(md5Hash, md5Hash);
+
+        for (String pw : noMatch.keySet()) {
+            u.changePassword(pw);
+
+            String plain = noMatch.get(pw);
+            SimpleCredentials sc = new SimpleCredentials(u.getID(), plain.toCharArray());
+            CryptedSimpleCredentials cc = (CryptedSimpleCredentials) u.getCredentials();
 
-            SimpleCredentials creds = new SimpleCredentials(user.getID(), "pw".toCharArray());
-            assertTrue(((CryptedSimpleCredentials) user.getCredentials()).matches(creds));
-        } finally {
-            user.changePassword(oldPw);
-            save(superuser);
+            assertFalse(cc.matches(sc));
+        }
+
+        // invalid pw string
+        try {
+            u.changePassword(null);
+            fail("invalid pw null");
+        } catch (Exception e) {
+            // success
         }
     }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java?rev=918412&r1=918411&r2=918412&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserManagerImplTest.java Wed Mar  3 11:13:27 2010
@@ -45,6 +45,7 @@
 
     private String pPrincipalName;
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         if (!(userMgr instanceof UserManagerImpl)) {
@@ -107,7 +108,7 @@
     public void testCreateUserIdDifferentFromPrincipalName() throws RepositoryException, NotExecutableException {
         Principal p = getTestPrincipal();
         String uid = getTestUserId(p);
-        String pw = buildPassword(uid, true);
+        String pw = buildPassword(uid);
 
         User u = null;
         Session uSession = null;
@@ -142,7 +143,7 @@
         User u = null;
         Group gr = null;
         try {
-            u = userMgr.createUser(uid, buildPassword(uid, true), p, null);
+            u = userMgr.createUser(uid, buildPassword(uid), p, null);
             save(superuser);
             gr = userMgr.createGroup(new TestPrincipal(uid));
             save(superuser);
@@ -177,7 +178,7 @@
 
                     // the result must contain 1 authorizable
                     assertTrue(users.hasNext());
-                    Authorizable first = (Authorizable) users.next();
+                    Authorizable first = users.next();
                     assertEquals(first.getID(), val);
 
                     // since id is unique -> there should be no more users in
@@ -221,7 +222,7 @@
         try {
             Principal p = getTestPrincipal();
             String uid = "UID" + p.getName();
-            u = userMgr.createUser(uid, buildPassword(uid, false), p, null);
+            u = userMgr.createUser(uid, buildPassword(uid), p, null);
             save(superuser);
 
             boolean found = false;
@@ -246,7 +247,7 @@
 
             it = userMgr.findAuthorizables(pPrincipalName, null, UserManager.SEARCH_TYPE_GROUP);
             while (it.hasNext()) {
-                if (((Authorizable) it.next()).getPrincipal().getName().equals(p.getName())) {
+                if (it.next().getPrincipal().getName().equals(p.getName())) {
                     fail("Searching for Groups should never find a user");
                 }
             }
@@ -285,7 +286,7 @@
 
             it = userMgr.findAuthorizables(pPrincipalName, null, UserManager.SEARCH_TYPE_USER);
             while (it.hasNext()) {
-                if (((Authorizable) it.next()).getPrincipal().getName().equals(p.getName())) {
+                if (it.next().getPrincipal().getName().equals(p.getName())) {
                     fail("Searching for Users should never find a group");
                 }
             }
@@ -313,7 +314,7 @@
 
     public void testNewUserCanLogin() throws RepositoryException, NotExecutableException {
         String uid = getTestPrincipal().getName();
-        String pw = buildPassword(uid, false);
+        String pw = buildPassword(uid);
 
         User u = null;
         Session s = null;
@@ -476,13 +477,13 @@
 
         String usersPath = ((UserManagerImpl) userMgr).getUsersPath();
 
-        List<String> invalid = new ArrayList();
+        List<String> invalid = new ArrayList<String>();
         invalid.add("../../path");
         invalid.add(usersPath + "/../test");
 
         for (String path : invalid) {
             try {
-                User user = userMgr.createUser(uid, buildPassword(uid, true), p, path);
+                User user = userMgr.createUser(uid, buildPassword(uid), p, path);
                 save(superuser);
 
                 fail("intermediate path may not point outside of the user tree.");
@@ -495,4 +496,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}