Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
************************************************************************
******************* CANADIAN ASTRONOMY DATA CENTRE *******************
************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES **************
*
* (c) 2014. (c) 2014.
* Government of Canada Gouvernement du Canada
* National Research Council Conseil national de recherches
* Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6
* All rights reserved Tous droits réservés
*
* NRC disclaims any warranties, Le CNRC dénie toute garantie
* expressed, implied, or énoncée, implicite ou légale,
* statutory, of any kind with de quelque nature que ce
* respect to the software, soit, concernant le logiciel,
* including without limitation y compris sans restriction
* any warranty of merchantability toute garantie de valeur
* or fitness for a particular marchande ou de pertinence
* purpose. NRC shall not be pour un usage particulier.
* liable in any event for any Le CNRC ne pourra en aucun cas
* damages, whether direct or être tenu responsable de tout
* indirect, special or general, dommage, direct ou indirect,
* consequential or incidental, particulier ou général,
* arising from the use of the accessoire ou fortuit, résultant
* software. Neither the name de l'utilisation du logiciel. Ni
* of the National Research le nom du Conseil National de
* Council of Canada nor the Recherches du Canada ni les noms
* names of its contributors may de ses participants ne peuvent
* be used to endorse or promote être utilisés pour approuver ou
* products derived from this promouvoir les produits dérivés
* software without specific prior de ce logiciel sans autorisation
* written permission. préalable et particulière
* par écrit.
*
* This file is part of the Ce fichier fait partie du projet
* OpenCADC project. OpenCADC.
*
* OpenCADC is free software: OpenCADC est un logiciel libre ;
* you can redistribute it and/or vous pouvez le redistribuer ou le
* modify it under the terms of modifier suivant les termes de
* the GNU Affero General Public la “GNU Affero General Public
* License as published by the License” telle que publiée
* Free Software Foundation, par la Free Software Foundation
* either version 3 of the : soit la version 3 de cette
* License, or (at your option) licence, soit (à votre gré)
* any later version. toute version ultérieure.
*
* OpenCADC is distributed in the OpenCADC est distribué
* hope that it will be useful, dans l’espoir qu’il vous
* but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE
* without even the implied GARANTIE : sans même la garantie
* warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ
* or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF
* PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence
* General Public License for Générale Publique GNU Affero
* more details. pour plus de détails.
*
* You should have received Vous devriez avoir reçu une
* a copy of the GNU Affero copie de la Licence Générale
* General Public License along Publique GNU Affero avec
* with OpenCADC. If not, see OpenCADC ; si ce n’est
* <http://www.gnu.org/licenses/>. pas le cas, consultez :
* <http://www.gnu.org/licenses/>.
*
* $Revision: 4 $
*
************************************************************************
*/
package ca.nrc.cadc.ac.server.ldap;
import ca.nrc.cadc.auth.AuthenticationUtil;
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.net.TransientException;
import com.unboundid.ldap.sdk.AddRequest;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl;
import java.security.AccessControlException;
import java.security.Principal;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Logger;
public class LdapUserDAO<T extends Principal> extends LdapDAO
{
private static final Logger logger = Logger.getLogger(LdapUserDAO.class);
private final Map<Class<?>, String> userLdapAttrib = new HashMap<Class<?>, String>();
// Returned User attributes
protected static final String LDAP_OBJECT_CLASS = "objectClass";
protected static final String LDAP_INET_ORG_PERSON = "inetOrgPerson";
protected static final String LDAP_CADC_ACCOUNT = "cadcaccount";
protected static final String LDAP_POSIX_ACCOUNT = "posixaccount";
protected static final String LDAP_NSACCOUNTLOCK = "nsaccountlock";
protected static final String LDAP_MEMBEROF = "memberOf";
protected static final String LDAP_ENTRYDN = "entrydn";
protected static final String LDAP_COMMON_NAME = "cn";
protected static final String LDAP_DISTINGUISHED_NAME = "distinguishedName";
protected static final String LADP_USER_PASSWORD = "userPassword";
protected static final String LDAP_FIRST_NAME = "givenName";
protected static final String LDAP_LAST_NAME = "sn";
protected static final String LDAP_ADDRESS = "address";
protected static final String LDAP_CITY = "city";
protected static final String LDAP_COUNTRY = "country";
protected static final String LDAP_EMAIL = "email";
protected static final String LDAP_INSTITUTE = "institute";
protected static final String LDAP_UID = "uid";
protected static final String LDAP_UID_NUMBER = "uidNumber";
protected static final String LDAP_GID_NUMBER = "gidNumber";
protected static final String LDAP_HOME_DIRECTORY = "homeDirectory";
protected static final String LDAP_LOGIN_SHELL = "loginShell";
private String[] userAttribs = new String[]
{
LDAP_FIRST_NAME, LDAP_LAST_NAME, LDAP_ADDRESS, LDAP_CITY, LDAP_COUNTRY,
LDAP_EMAIL, LDAP_INSTITUTE, LDAP_UID, LDAP_UID_NUMBER, LDAP_GID_NUMBER,
LDAP_HOME_DIRECTORY, LDAP_LOGIN_SHELL
};
private String[] memberAttribs = new String[]
{
LDAP_FIRST_NAME, LDAP_LAST_NAME
};
public LdapUserDAO(LdapConfig config)
{
super(config);
this.userLdapAttrib.put(HttpPrincipal.class, LDAP_UID);
this.userLdapAttrib.put(X500Principal.class, LDAP_DISTINGUISHED_NAME);
// add the id attributes to user and member attributes
String[] princs = userLdapAttrib.values()
.toArray(new String[userLdapAttrib.values().size()]);
String[] tmp = new String[userAttribs.length + princs.length];
System.arraycopy(princs, 0, tmp, 0, princs.length);
System.arraycopy(userAttribs, 0, tmp, princs.length,
userAttribs.length);
tmp = new String[memberAttribs.length + princs.length];
System.arraycopy(princs, 0, tmp, 0, princs.length);
System.arraycopy(memberAttribs, 0, tmp, princs.length,
memberAttribs.length);
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
*
* @return
* @throws TransientException
*/
public Collection<HttpPrincipal> getCadcIDs() throws TransientException
{
try
{
Filter filter = Filter.createPresenceFilter("uid");
String [] attributes = new String[] {"uid"};
SearchRequest searchRequest =
new SearchRequest(config.getUsersDN(),
SearchScope.SUB, filter, attributes);
SearchResult searchResult = null;
try
{
searchResult = getConnection().search(searchRequest);
}
catch (LDAPSearchException e)
{
if (e.getResultCode() == ResultCode.NO_SUCH_OBJECT)
{
logger.debug("Could not find users root", e);
throw new IllegalStateException("Could not find users root");
}
}
LdapDAO.checkLdapResult(searchResult.getResultCode());
Collection<HttpPrincipal> userIDs = new HashSet<HttpPrincipal>();
for (SearchResultEntry next : searchResult.getSearchEntries())
{
userIDs.add(new HttpPrincipal(next.getAttributeValue("uid")));
}
return userIDs;
}
catch (LDAPException e1)
{
logger.debug("getCadcIDs Exception: " + e1, e1);
LdapDAO.checkLdapResult(e1.getResultCode());
throw new IllegalStateException("Unexpected exception: " +
e1.getMatchedDN(), e1);
}
}
Brian Major
committed
/**
* Add the specified user..
*
* @param userRequest The user to add.
* @return User instance.
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
public User<T> addUser(final UserRequest<T> userRequest)
final User<T> user = userRequest.getUser();
final Class userType = user.getUserID().getClass();
String searchField = userLdapAttrib.get(userType);
if (searchField == null)
{
throw new IllegalArgumentException("Unsupported principal type " + userType);
}
try
{
// add new user
DN userDN = getUserRequestsDN(user.getUserID().getName());
List<Attribute> attributes = new ArrayList<Attribute>();
addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_ORG_PERSON);
addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_CADC_ACCOUNT);
addAttribute(attributes, LDAP_COMMON_NAME, user.getUserID().getName());
addAttribute(attributes, LDAP_DISTINGUISHED_NAME, userDN.toNormalizedString());
addAttribute(attributes, LADP_USER_PASSWORD, userRequest.getPassword());
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
for (UserDetails details : user.details)
{
if (details.getClass() == PersonalDetails.class)
{
PersonalDetails pd = (PersonalDetails) details;
addAttribute(attributes, LDAP_FIRST_NAME, pd.getFirstName());
addAttribute(attributes, LDAP_LAST_NAME, pd.getLastName());
addAttribute(attributes, LDAP_ADDRESS, pd.address);
addAttribute(attributes, LDAP_CITY, pd.city);
addAttribute(attributes, LDAP_COUNTRY, pd.country);
addAttribute(attributes, LDAP_EMAIL, pd.email);
addAttribute(attributes, LDAP_INSTITUTE, pd.institute);
}
else if (details.getClass() == PosixDetails.class)
{
PosixDetails pd = (PosixDetails) details;
addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_POSIX_ACCOUNT);
addAttribute(attributes, LDAP_UID, Long.toString(pd.getUid()));
addAttribute(attributes, LDAP_UID_NUMBER, Long.toString(pd.getUid()));
addAttribute(attributes, LDAP_GID_NUMBER, Long.toString(pd.getGid()));
addAttribute(attributes, LDAP_HOME_DIRECTORY, pd.getHomeDirectory());
addAttribute(attributes, LDAP_LOGIN_SHELL, pd.loginShell);
}
}
AddRequest addRequest = new AddRequest(userDN, attributes);
LDAPResult result = getConnection().add(addRequest);
LdapDAO.checkLdapResult(result.getResultCode());
// AD: Search results sometimes come incomplete if
// connection is not reset - not sure why.
getConnection().reconnect();
try
{
return getUser(user.getUserID(), config.getUserRequestsDN());
}
catch (UserNotFoundException e)
{
throw new RuntimeException("BUG: new user " + userDN.toNormalizedString() +
" not found, result " + result.getResultCode());
}
}
catch (LDAPException e)
{
System.out.println("LDAPe: " + e);
System.out.println("LDAPrc: " + e.getResultCode());
logger.debug("addUser Exception: " + e, e);
LdapDAO.checkLdapResult(e.getResultCode());
throw new RuntimeException("Unexpected LDAP exception", e);
}
}
* @throws UserNotFoundException when the user is not found.
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
public User<T> getUser(final T userID)
throws UserNotFoundException, TransientException, AccessControlException
{
return getUser(userID, config.getUsersDN());
}
/**
* Get the user specified by userID.
*
* @param userID The userID.
* @param usersDN The LDAP tree to search.
* @return User instance.
* @throws UserNotFoundException when the user is not found.
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
private User<T> getUser(final T userID, final String usersDN)
throws UserNotFoundException, TransientException, AccessControlException
String searchField = userLdapAttrib.get(userID.getClass());
throw new IllegalArgumentException(
"Unsupported principal type " + userID.getClass());
searchField = "(&(objectclass=inetorgperson)(" +
searchField + "=" + userID.getName() + "))";
SearchResultEntry searchResult = null;
try
{
new SearchRequest(usersDN, SearchScope.SUB,
new ProxiedAuthorizationV2RequestControl(
"dn:" + getSubjectDN().toNormalizedString()));
searchResult = getConnection().searchForEntry(searchRequest);
}
catch (LDAPException e)
{
LdapDAO.checkLdapResult(e.getResultCode());
}
if (searchResult == null)
{
String msg = "User not found " + userID.toString();
logger.debug(msg);
throw new UserNotFoundException(msg);
}
user.getIdentities().add(new HttpPrincipal(searchResult
.getAttributeValue(userLdapAttrib.get(HttpPrincipal.class))));
String fname = searchResult.getAttributeValue(LDAP_FIRST_NAME);
String lname = searchResult.getAttributeValue(LDAP_LAST_NAME);
PersonalDetails personaDetails = new PersonalDetails(fname, lname);
personaDetails.address = searchResult.getAttributeValue(LDAP_ADDRESS);
personaDetails.city = searchResult.getAttributeValue(LDAP_CITY);
personaDetails.country = searchResult.getAttributeValue(LDAP_COUNTRY);
personaDetails.email = searchResult.getAttributeValue(LDAP_EMAIL);
personaDetails.institute = searchResult.getAttributeValue(LDAP_INSTITUTE);
user.details.add(personaDetails);
Long uid = searchResult.getAttributeValueAsLong(LDAP_UID_NUMBER);
Long gid = searchResult.getAttributeValueAsLong(LDAP_GID_NUMBER);
String homeDirectory = searchResult.getAttributeValue(LDAP_HOME_DIRECTORY);
if (uid != null && gid != null && homeDirectory != null)
{
PosixDetails posixDetails = new PosixDetails(uid, gid, homeDirectory);
posixDetails.loginShell = searchResult.getAttributeValue(LDAP_LOGIN_SHELL);
user.details.add(posixDetails);
}
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
/**
* Get all group names.
*
* @return A collection of strings
*
* @throws TransientException If an temporary, unexpected problem occurred.
*/
public Collection<String> getUserNames()
throws TransientException
{
try
{
Filter filter = Filter.createPresenceFilter(LDAP_COMMON_NAME);
String [] attributes = new String[] {LDAP_COMMON_NAME, LDAP_NSACCOUNTLOCK};
SearchRequest searchRequest =
new SearchRequest(config.getGroupsDN(),
SearchScope.SUB, filter, attributes);
SearchResult searchResult = null;
try
{
searchResult = getConnection().search(searchRequest);
}
catch (LDAPSearchException e)
{
if (e.getResultCode() == ResultCode.NO_SUCH_OBJECT)
{
logger.debug("Could not find groups root", e);
throw new IllegalStateException("Could not find groups root");
}
}
LdapDAO.checkLdapResult(searchResult.getResultCode());
List<String> groupNames = new ArrayList<String>();
for (SearchResultEntry next : searchResult.getSearchEntries())
{
if (!next.hasAttribute(LDAP_NSACCOUNTLOCK))
{
groupNames.add(next.getAttributeValue(LDAP_COMMON_NAME));
}
}
return groupNames;
}
catch (LDAPException e1)
{
logger.debug("getGroupNames Exception: " + e1, e1);
LdapDAO.checkLdapResult(e1.getResultCode());
throw new IllegalStateException("Unexpected exception: " + e1.getMatchedDN(), e1);
}
}
/**
* Updated the user specified by User.
*
* @param user
*
* @return User instance.
*
* @throws UserNotFoundException when the user is not found.
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
public User<T> modifyUser(User<T> user)
throws UserNotFoundException, TransientException,
AccessControlException
{
return null;
}
/**
* Delete the user specified by userID.
*
* @param userID The userID.
*
* @throws UserNotFoundException when the user is not found.
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
public void deleteUser(final T userID)
throws UserNotFoundException, TransientException,
AccessControlException
{
}
/**
* Get all groups the user specified by userID belongs to.
* @return Collection of Group instances.
* @throws UserNotFoundException when the user is not found.
* @throws TransientException If an temporary, unexpected problem occurred., e.getMessage(
* @throws AccessControlException If the operation is not permitted.
*/
public Collection<DN> getUserGroups(final T userID, final boolean isAdmin)
throws UserNotFoundException, TransientException,
AccessControlException
String searchField = userLdapAttrib.get(userID.getClass());
if (searchField == null)
{
throw new IllegalArgumentException(
"Unsupported principal type " + userID.getClass());
}
Filter.createEqualityFilter(searchField,
user.getUserID().getName()),
Filter.createPresenceFilter(LDAP_MEMBEROF));
SearchRequest searchRequest =
new SearchRequest(config.getUsersDN(), SearchScope.SUB,
new ProxiedAuthorizationV2RequestControl("dn:" +
getSubjectDN()
.toNormalizedString()));
DN parentDN;
if (isAdmin)
{
parentDN = new DN(config.getAdminGroupsDN());
}
else
{
parentDN = new DN(config.getGroupsDN());
}
String[] members = searchResult.getAttributeValues(LDAP_MEMBEROF);
if (members != null)
{
for (String member : members)
{
DN groupDN = new DN(member);
if (groupDN.isDescendantOf(parentDN, false))
LdapDAO.checkLdapResult(e.getResultCode());
/**
* Check whether the user is a member of the group.
*
* @param groupID The groupID.
* @return true or false
* @throws UserNotFoundException If the user is not found.
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
public boolean isMember(T userID, String groupID)
throws UserNotFoundException, TransientException,
AccessControlException
String searchField = userLdapAttrib.get(userID.getClass());
if (searchField == null)
{
throw new IllegalArgumentException(
"Unsupported principal type " + userID.getClass());
}
User<T> user = getUser(userID);
Filter.createEqualityFilter(searchField,
user.getUserID().getName()),
Filter.createEqualityFilter(LDAP_MEMBEROF, groupID));
SearchRequest searchRequest =
new SearchRequest(config.getUsersDN(), SearchScope.SUB,
new ProxiedAuthorizationV2RequestControl("dn:" +
getSubjectDN()
.toNormalizedString()));
SearchResultEntry searchResults =
LdapDAO.checkLdapResult(e.getResultCode());
* Returns a member user identified by the X500Principal only. The
* returned object has the fields required by the GMS.
* Note that this method binds as a proxy user and not as the
* @param userDN
* @return
* @throws UserNotFoundException
* @throws LDAPException
*/
User<X500Principal> getMember(DN userDN)
Filter.createEqualityFilter(LDAP_ENTRYDN,
userDN.toNormalizedString());
SearchRequest searchRequest =
new SearchRequest(this.config.getUsersDN(), SearchScope.SUB,
Jeff Burke
committed
getConnection().searchForEntry(searchRequest);
String msg = "Member not found " + userDN;
logger.debug(msg);
throw new UserNotFoundException(msg);
}
User<X500Principal> user = new User<X500Principal>(
new X500Principal(searchResult.getAttributeValue(
String princ = searchResult.getAttributeValue(
if (princ != null)
{
user.getIdentities().add(new HttpPrincipal(princ));
}
String fname = searchResult.getAttributeValue(LDAP_FIRST_NAME);
String lname = searchResult.getAttributeValue(LDAP_LAST_NAME);
user.details.add(new PersonalDetails(fname, lname));
DN getUserDN(User<? extends Principal> user)
throws UserNotFoundException, TransientException
String searchField =
userLdapAttrib.get(user.getUserID().getClass());
"Unsupported principal type " + user.getUserID()
.getClass());
// change the DN to be in the 'java' format
if (user.getUserID() instanceof X500Principal)
{
X500Principal orderedPrincipal = AuthenticationUtil.getOrderedForm(
(X500Principal) user.getUserID());
searchField = "(" + searchField + "=" + orderedPrincipal.toString() + ")";
}
else
{
searchField = "(" + searchField + "=" + user.getUserID().getName()
+ ")";
}
logger.debug("Search field is: " + searchField);
SearchResultEntry searchResult = null;
try
{
SearchRequest searchRequest =
new SearchRequest(this.config.getUsersDN(), SearchScope.SUB,
searchResult =
getConnection().searchForEntry(searchRequest);
}
catch (LDAPException e)
LdapDAO.checkLdapResult(e.getResultCode());
String msg = "User not found " + user.getUserID().getName();
logger.debug(msg);
throw new UserNotFoundException(msg);
}
return searchResult.getAttributeValueAsDN(LDAP_ENTRYDN);
}
protected DN getUserDN(final String userID)
throws LDAPException, TransientException
{
try
{
return new DN(LDAP_UID + "=" + userID + "," + config.getUsersDN());
}
catch (LDAPException e)
{
logger.debug("getUserDN Exception: " + e, e);
LdapDAO.checkLdapResult(e.getResultCode());
}
throw new IllegalArgumentException(userID + " not a valid user ID");
}
protected DN getUserRequestsDN(final String userID)
throws LDAPException, TransientException
{
try
{
return new DN(LDAP_UID + "=" + userID + "," + config.getUserRequestsDN());
}
catch (LDAPException e)
{
logger.debug("getUserRequestsDN Exception: " + e, e);
LdapDAO.checkLdapResult(e.getResultCode());
}
throw new IllegalArgumentException(userID + " not a valid user ID");
}
void addAttribute(List<Attribute> attributes, final String name, final String value)
{
if (value != null && !value.isEmpty())
{
attributes.add(new Attribute(name, value));
}