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 020package org.apache.james.user.ldap; 021 022import java.io.Serializable; 023 024import javax.naming.Context; 025import javax.naming.NamingException; 026import javax.naming.ldap.LdapContext; 027 028import org.apache.james.user.api.model.User; 029import 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 */ 045public 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 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) { 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 . 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}