Package org.apache.james.user.jcr

Source Code of org.apache.james.user.jcr.JCRUsersRepository

/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one   *
* or more contributor license agreements.  See the NOTICE file *
* distributed with this work for additional information        *
* regarding copyright ownership.  The ASF licenses this file   *
* to you under the Apache License, Version 2.0 (the            *
* "License"); you may not use this file except in compliance   *
* with the License.  You may obtain a copy of the License at   *
*                                                              *
*   http://www.apache.org/licenses/LICENSE-2.0                 *
*                                                              *
* Unless required by applicable law or agreed to in writing,   *
* software distributed under the License is distributed on an  *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
* KIND, either express or implied.  See the License for the    *
* specific language governing permissions and limitations      *
* under the License.                                           *
****************************************************************/

package org.apache.james.user.jcr;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.annotation.Resource;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.logging.Log;
import org.apache.jackrabbit.util.ISO9075;
import org.apache.jackrabbit.util.Text;
import org.apache.james.lifecycle.Configurable;
import org.apache.james.lifecycle.LogEnabled;
import org.apache.james.user.api.User;
import org.apache.james.user.api.UsersRepository;
import org.apache.james.user.jcr.model.JCRUser;

/**
* {@link UsersRepository} implementation which stores users to a JCR {@link Repository}
*
*/
public class JCRUsersRepository implements UsersRepository, Configurable, LogEnabled {
   
    //TODO: Add namespacing
    private static final String PASSWD_PROPERTY = "passwd";

    private static final String USERNAME_PROPERTY = "username";
    private static final String USERS_PATH = "users";

  private Repository repository;
  private SimpleCredentials creds;
  private String workspace;

  private Log logger;
 
    @Resource(name="jcrRepository")
    public void setRepository(Repository repository) {
      this.repository = repository;
    }
   
    /*
     * (non-Javadoc)
     * @see org.apache.james.lifecycle.Configurable#configure(org.apache.commons.configuration.HierarchicalConfiguration)
     */
  public void configure(HierarchicalConfiguration config)
      throws ConfigurationException {
    this.workspace = config.getString("workspace",null);
    String username = config.getString("username", null);
    String password = config.getString("password",null);
   
    if (username != null && password != null) {
      this.creds = new SimpleCredentials(username, password.toCharArray());
    }
  }


  /*
   * (non-Javadoc)
   * @see org.apache.james.lifecycle.LogEnabled#setLog(org.apache.commons.logging.Log)
   */
  public void setLog(Log log) {   
    this.logger = log;
  }

    /**
     * Adds a user to the repository with the specified User object.
     *
     * @param user the user to be added
     *
     * @return true if succesful, false otherwise
     *
     * @deprecated James 2.4 user should be added using username/password
     * because specific implementations of UsersRepository will support specific
     * implementations of users object.
     */
    public boolean addUser(User user) {
        throw new UnsupportedOperationException("Unsupported by JCR");
    }

    /**
     * Adds a user to the repository with the specified attributes.  In current
     * implementations, the Object attributes is generally a String password.
     *
     * @param name the name of the user to be added
     * @param attributes see decription
     *
     * @deprecated James 2.4 user is always added using username/password and
     * eventually modified by retrieving it later.
     */
    public void addUser(String name, Object attributes) {
        if (attributes instanceof String) {
            addUser(name, (String) attributes);
        } else {
            throw new IllegalArgumentException("Expected password string");
        }
    }
   
    /**
     * Adds a user to the repository with the specified password
     *
     * @param username the username of the user to be added
     * @param password the password of the user to add
     * @return true if succesful, false otherwise
     *
     */
    public boolean addUser(String username, String password) {

        try {
            final Session session = login();
            try {
                final String name = toSafeName(username);
                final String path = USERS_PATH + "/" + name;
                final Node rootNode = session.getRootNode();
                try {
                    rootNode.getNode(path);
                    logger.info("User already exists");
                    return false;
                } catch (PathNotFoundException e) {
                    // user does not exist
                }
                Node parent;
                try {
                    parent = rootNode.getNode(USERS_PATH);
                } catch (PathNotFoundException e) {
                    // TODO: Need to consider whether should insist that parent
                    // TODO: path exists.
                    parent = rootNode.addNode(USERS_PATH);
                }
               
                Node node = parent.addNode(name);
                node.setProperty(USERNAME_PROPERTY, username);
                final String hashedPassword;
                if (password == null)
                {
                    // Support easy password reset
                    hashedPassword = "";
                }
                else
                {
                    hashedPassword = JCRUser.hashPassword(username, password);
                }
                node.setProperty(PASSWD_PROPERTY, hashedPassword);
                session.save();
                return true;
            } finally {
                session.logout();
            }
           
        } catch (RepositoryException e) {
            if (logger.isInfoEnabled()) {
                logger.info("Failed to add user: " + username, e);
            }
        }

        return false;
    }
   
    protected String toSafeName(String key) {
        String name = ISO9075.encode(Text.escapeIllegalJcrChars(key));
        return name;
    }
   
    private Session login() throws RepositoryException{
      return repository.login(creds, workspace);
    }
   
    /**
     * Get the user object with the specified user name.  Return null if no
     * such user.
     *
     * @param name the name of the user to retrieve
     * @return the user being retrieved, null if the user doesn't exist
     *
     */
    public User getUserByName(String username) {
        User user;
        try {
            final Session session = login();
            try {
                final String name = toSafeName(username);
                final String path = USERS_PATH + "/" + name;
                final Node rootNode = session.getRootNode();
               
                try {
                    final Node node = rootNode.getNode(path);
                    user = new JCRUser(node.getProperty(USERNAME_PROPERTY).getString(),
                            node.getProperty(PASSWD_PROPERTY).getString());
                } catch (PathNotFoundException e) {
                    // user not found
                    user = null;
                }
            } finally {
                session.logout();
            }
           
        } catch (RepositoryException e) {
            if (logger.isInfoEnabled()) {
                logger.info("Failed to add user: " + username, e);
            }
            user = null;
        }
        return user;
    }

    /**
     * Get the user object with the specified user name. Match user naems on
     * a case insensitive basis.  Return null if no such user.
     *
     * @param name the name of the user to retrieve
     * @return the user being retrieved, null if the user doesn't exist
     *
     * @since James 1.2.2
     * @deprecated James 2.4 now caseSensitive is a property of the repository
     * implementations and the getUserByName will search according to this property.
     */
    public User getUserByNameCaseInsensitive(String name) {
        throw new UnsupportedOperationException();
    }

    /**
     * Returns the user name of the user matching name on an equalsIgnoreCase
     * basis. Returns null if no match.
     *
     * @param name the name to case-correct
     * @return the case-correct name of the user, null if the user doesn't exist
     */
    public String getRealName(String name) {
        return null;
    }

    /**
     * Update the repository with the specified user object. A user object
     * with this username must already exist.
     *
     * @return true if successful.
     */
    public boolean updateUser(final User user) {
        if (user != null && user instanceof JCRUser)
        {
            final JCRUser jcrUser = (JCRUser) user;
            final String userName = jcrUser.getUserName();
            try {
                final Session session = login();
                try {
                    final String name = toSafeName(userName);
                    final String path = USERS_PATH + "/" + name;
                    final Node rootNode = session.getRootNode();
                   
                    try {
                        final String hashedSaltedPassword = jcrUser.getHashedSaltedPassword();
                        rootNode.getNode(path).setProperty(PASSWD_PROPERTY, hashedSaltedPassword);
                        session.save();
                        return true;
                    } catch (PathNotFoundException e) {
                        // user not found
                        logger.debug("User not found");
                    }
                } finally {
                    session.logout();
                }
               
            } catch (RepositoryException e) {
                if (logger.isInfoEnabled()) {
                    logger.info("Failed to add user: " + userName, e);
                }
            }
        }
        return false;
    }

    /**
     * Removes a user from the repository
     *
     * @param name the user to remove from the repository
     */
    public void removeUser(String username) {
        try {
            final Session session = login();
            try {
                final String name = toSafeName(username);
                final String path = USERS_PATH + "/" + name;
                try {
                    session.getRootNode().getNode(path).remove();
                    session.save();
                } catch (PathNotFoundException e) {
                    // user not found
                }
            } finally {
                session.logout();
            }
           
        } catch (RepositoryException e) {
            if (logger.isInfoEnabled()) {
                logger.info("Failed to add user: " + username, e);
            }
        }
    }

    /**
     * Returns whether or not this user is in the repository
     *
     * @param name the name to check in the repository
     * @return whether the user is in the repository
     */
    public boolean contains(String name) {
        try {
            final Session session = login();
            try {
                final Node rootNode = session.getRootNode();
                final String path = USERS_PATH + "/" + toSafeName(name);               
                rootNode.getNode(path);
                return true;
            } finally {
                session.logout();
            }
           
        } catch (RepositoryException e) {
            if (logger.isDebugEnabled()) {
                logger.debug("User not found: " + name, e);
            }
        }

        return false;
    }

    /**
     * Returns whether or not this user is in the repository. Names are
     * matched on a case insensitive basis.
     *
     * @param name the name to check in the repository
     * @return whether the user is in the repository
     *
     * @deprecated James 2.4 now caseSensitive is a property of the repository
     * implementations and the contains will search according to this property.
     */
    public boolean containsCaseInsensitive(String name) {
        throw new UnsupportedOperationException();
    }

    /**
     * Test if user with name 'name' has password 'password'.
     *
     * @param name the name of the user to be tested
     * @param password the password to be tested
     *
     * @return true if the test is successful, false if the user
     *              doesn't exist or if the password is incorrect
     *
     * @since James 1.2.2
     */
    public boolean test(String username, String password) {
        try {
            final Session session = login();
            try {
                final String name = toSafeName(username);
                final String path = USERS_PATH + "/" + name;
                final Node rootNode = session.getRootNode();
               
                try {
                    final Node node = rootNode.getNode(path);
                    final String current = node.getProperty(PASSWD_PROPERTY).getString();
                    if (current == null || current == "")
                    {
                        return password == null || password == "";
                    }
                    final String hashPassword = JCRUser.hashPassword(username, password);
                    return current.equals(hashPassword);
                } catch (PathNotFoundException e) {
                    // user not found
                    logger.debug("User not found");
                    return false;
                }
            } finally {
                session.logout();
            }
           
        } catch (RepositoryException e) {
            if (logger.isInfoEnabled()) {
                logger.info("Failed to add user: " + username, e);
            }
            return false;
        }

    }

    /**
     * Returns a count of the users in the repository.
     *
     * @return the number of users in the repository
     */
    public int countUsers() {
        try {
            final Session session = login();
            try {
                final Node rootNode = session.getRootNode();
                try {
                    final Node node = rootNode.getNode(USERS_PATH);
                    //TODO: Use query
                    //TODO: Use namespacing to avoid unwanted nodes
                    NodeIterator it = node.getNodes();
                    return (int) it.getSize();
                } catch (PathNotFoundException e) {
                    return 0;
                }
            } finally {
                session.logout();
            }
        } catch (RepositoryException e) {
            if (logger.isInfoEnabled()) {
                logger.info("Failed to count user", e);
            }
            return 0;
        }
    }

    /**
     * List users in repository.
     *
     * @return Iterator over a collection of Strings, each being one user in the repository.
     */
    public Iterator<String> list() {
        final Collection<String> userNames = new ArrayList<String>();
        try {
            final Session session = login();
            try {
                final Node rootNode = session.getRootNode();
                try {
                    final Node baseNode = rootNode.getNode(USERS_PATH);
                    //TODO: Use query
                    final NodeIterator it = baseNode.getNodes();
                    while(it.hasNext()) {
                        final Node node = it.nextNode();
                        try {
                            final String userName = node.getProperty(USERNAME_PROPERTY).getString();
                            userNames.add(userName);
                        } catch (PathNotFoundException e) {
                            logger.info("Node missing user name. Ignoring.");
                        }
                    }
                } catch (PathNotFoundException e) {
                    logger.info("Path not found. Forgotten to setup the repository?");
                }
            } finally {
                session.logout();
            }
        } catch (RepositoryException e) {
            if (logger.isInfoEnabled()) {
                logger.info("Failed to count user", e);
            }
        }
        return userNames.iterator();
    }

}
TOP

Related Classes of org.apache.james.user.jcr.JCRUsersRepository

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.