001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    package org.apache.james.user.ldap;
021    
022    import java.io.Serializable;
023    
024    import javax.naming.Context;
025    import javax.naming.NamingException;
026    import javax.naming.ldap.LdapContext;
027    
028    import org.apache.james.user.api.model.User;
029    import org.apache.james.user.ldap.api.LdapConstants;
030    
031    /**
032     * Encapsulates the details of a user as taken from an LDAP compliant directory.
033     * Instances of this class are only applicable to the
034     * {@link ReadOnlyUsersLDAPRepository} or its subclasses. Consequently it does
035     * not permit the mutation of user details. It is intended purely as an
036     * encapsulation of the user information as held in the LDAP directory, and as a
037     * means of authenticating the user against the LDAP server. Consequently
038     * invocations of the contract method {@link User#setPassword(String)} always
039     * returns <code>false</code>.
040     * 
041     * @see SimpleLDAPConnection
042     * @see ReadOnlyUsersLDAPRepository
043     * 
044     */
045    public class ReadOnlyLDAPUser implements User, Serializable {
046        // private static final long serialVersionUID = -6712066073820393235L; 
047        private static final long serialVersionUID = -5201235065842464013L;
048    
049        /**
050         * The user's identifier or name. This is the value that is returned by the
051         * method {@link User#getUserName()}. It is also from this value that the
052         * user's email address is formed, so for example: if the value of this
053         * field is <code>&quot;john.bold&quot;</code>, and the domain is
054         * <code>&quot;myorg.com&quot;</code>, the user's email address will be
055         * <code>&quot;john.bold&#64;myorg.com&quot;</code>.
056         */
057        private String _userName;
058    
059        /**
060         * The distinguished name of the user-record in the LDAP directory.
061         */
062        private String _userDN;
063    
064        /**
065         * The context for the LDAP server from which to retrieve the
066         * user's details.
067         */
068        private LdapContext _ldapContext = null;
069    
070        /**
071         * Creates a new instance of ReadOnlyLDAPUser.
072         *
073         */
074        private ReadOnlyLDAPUser() {
075            super();
076        }
077    
078        /**
079         * Constructs an instance for the given user-details, and which will
080         * authenticate against the given host.
081         * 
082         * @param userName
083         *            The user-identifier/name. This is the value with which the
084         *            field {@link #userName} will be initialised, and which will be
085         *            returned by invoking {@link #getUserName()}.
086         * @param userDN
087         *            The distinguished (unique-key) of the user details as stored
088         *            on the LDAP directory.
089         * @param ldapContext
090         *            The context for the LDAP server on which the user details are held.
091         *            This is also the host against which the user will be
092         *            authenticated, when {@link #verifyPassword(String)} is
093         *            invoked.
094         * @throws NamingException 
095         */
096        public ReadOnlyLDAPUser(String userName, String userDN, LdapContext ldapContext) throws NamingException {
097            this();
098            _userName = userName;
099            _userDN = userDN;
100            _ldapContext = ldapContext;
101        }
102    
103        /**
104         * Fulfils the contract {@link User#getUserName()}. It returns the value of
105         * the field {@link #userName}. This is generally the value from which the
106         * user email address is built, by appending the domain name to it.
107         * 
108         * @return The user's identifier or name.
109         */
110        public String getUserName() {
111            return _userName;
112        }
113    
114        /**
115         * Implementation of contract {@link User#setPassword(String)}, which is
116         * provided for compliance purposes only. Instances of this type mirror LDAP
117         * data and do not perform any updates to the directory. Consequently, this
118         * method always returns <code>false</code> and does not do any work.
119         * 
120         * @return <code>False</code>
121         */
122        public boolean setPassword(String newPass) {
123            return false;
124        }
125    
126        /**
127         * Verifies that the password supplied is actually the user's password, by
128         * attempting to rebind to a copy of the LDAP server context using the user's 
129         * username and the supplied password.
130         * 
131         * @param password
132         *            The password to validate.
133         * @return <code>True</code> if a connection can successfully be established
134         *         to the LDAP host using the user's id and the supplied password,
135         *         and <code>False</code> otherwise.
136         */
137        public boolean verifyPassword(String password) {
138            boolean result = false;
139            LdapContext ldapContext = null;
140            try {
141                ldapContext = _ldapContext.newInstance(null);
142                ldapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION,
143                        LdapConstants.SECURITY_AUTHENTICATION_SIMPLE);
144                ldapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, _userDN);
145                ldapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
146                ldapContext.reconnect(null);
147                result = true;
148            } catch (NamingException exception) {
149                // no-op
150            } finally {
151                if (null != ldapContext) {
152                    try {
153                        ldapContext.close();
154                    } catch (NamingException ex) {
155                        // no-op
156                    }
157                }
158            }
159            return result;
160        }
161    }