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>"john.bold"</code>, and the domain is
054 * <code>"myorg.com"</code>, the user's email address will be
055 * <code>"john.bold@myorg.com"</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 }