/*
* 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 nl.surfnet.coin.ldap;
import java.util.Collection;
import java.util.List;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import nl.surfnet.coin.api.client.domain.Account;
import nl.surfnet.coin.api.client.domain.Email;
import nl.surfnet.coin.api.client.domain.Name;
import nl.surfnet.coin.api.client.domain.Organization;
import nl.surfnet.coin.api.client.domain.Person;
import nl.surfnet.coin.eb.EngineBlock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.Filter;
import org.springframework.ldap.filter.OrFilter;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* Interface to Ldap where all persons are stored.
*
*/
public class LdapClientImpl implements LdapClient {
private static final Logger LOG = LoggerFactory.getLogger(LdapClientImpl.class);
@Autowired
private LdapOperations ldapOperations;
@Autowired
private EngineBlock engineBlock;
/**
*
* Find the Person in the LDAP. The identifier can either be the urn
* (urn:collab:person:nl.myuniversity:s123456) or the persistent identifier
* (hashed urn specific for the SP).
*
* @param identifier
* unique identifier of the Person
* @return Person object
*/
@Override
@SuppressWarnings("unchecked")
public Person findPerson(String identifier) {
Filter query = getFilter(identifier);
List<Person> search = findPersons(query);
if (CollectionUtils.isEmpty(search)) {
return null;
}
if (search.size() > 1) {
throw new RuntimeException("Found more then one LDAP entry for identifier(" + query.toString() + ")");
}
return search.get(0);
}
/* (non-Javadoc)
* @see nl.surfnet.coin.ldap.LdapClient#findPersons(java.util.Collection)
*/
@Override
public List<Person> findPersons(Collection<String> identifiers) {
Filter query = getFilter(identifiers.toArray(new String[identifiers.size()]));
List<Person> search = findPersons(query);
return search;
}
private List<Person> findPersons(Filter query) {
AndFilter filter = new AndFilter().and(new EqualsFilter("objectclass", "collabPerson")).and(
query);
String encode = filter.encode();
LOG.debug("Encoded filter while searching LDAP: {}", encode);
List<Person> search = (List<Person>) ldapOperations.search("", encode, new AttributesMapper() {
@Override
public Person mapFromAttributes(Attributes attributes) throws NamingException {
return convertLdapProperties(new Person(), attributes);
}
});
LOG.debug("Got {} results from LDAP query", (search == null ? null : search.size()));
return search;
}
private Filter getFilter(String... identifiers) {
OrFilter orFilter = new OrFilter();
for (String identifier : identifiers) {
Assert.hasText(identifier, "Identifier may not be null or empty when searching for a Person");
String searchAttribute = "collabpersonid";
if (!identifier.startsWith(URN_IDENTIFIER)) {
searchAttribute = "collabpersonuuid";
identifier = engineBlock.getUserUUID(identifier);
}
orFilter.or(new EqualsFilter(searchAttribute, identifier));
}
return orFilter;
}
/*
* "collabpersonid" => "id" , 'collabpersonisguest' => 'person.tags', 'uid' =>
* array( 'account.username', 'account.userId', ), "givenname" =>
* "name.givenName", 'sn' => 'name.familyName', 'cn' => 'name.formatted',
* "displayname" => array( "displayName", "nickname" ) , "mail" => "emails",
* 'o' => 'organizations.name', 'schachomeorganizationtype' =>
* 'organizations.type', 'nledupersonorgunit' => 'organizations.department',
* 'edupersonaffiliation' => 'organizations.title',
*/
protected Person convertLdapProperties(Person person, Attributes attributes) {
person.setId(getAttribute("collabpersonid", attributes));
person.addTag(Boolean.valueOf(getAttribute("collabpersonisguest", attributes)) ? "guest" : "member");
String uid = getAttribute("uid", attributes);
if (StringUtils.hasText(uid)) {
person.addAccount(new Account(uid, uid));
}
person.setName(new Name(getAttribute("cn", attributes), getAttribute("sn", attributes), getAttribute("givenname",
attributes)));
person.setDisplayName(getAttribute("displayname", attributes));
person.setNickname(getAttribute("displayname", attributes));
String mail = getAttribute("mail", attributes);
if (StringUtils.hasText(mail)) {
person.addEmail(new Email(mail));
}
person.addOrganization(new Organization(getAttribute("o", attributes),
getAttribute("schachomeorganizationtype", attributes),
getAttribute("nledupersonorgunit", attributes),
getAttribute("edupersonaffiliation", attributes)));
return person;
}
/**
* Save get of an Attribute value, may return null
* @param attrID the attribute id
* @param attributes the attributes holder to get it from
* @return the stringified attribute or null.
*/
private String getAttribute(String attrID, Attributes attributes) {
Attribute attribute = attributes.get(attrID);
try {
return attribute != null ? (String) attribute.get() : null;
} catch (NamingException e) {
// ignore this as we can't recover
return null;
}
}
/**
* @param ldapOperations
* the ldapOperations to set
*/
public void setLdapOperations(LdapOperations ldapOperations) {
this.ldapOperations = ldapOperations;
}
/**
* @param engineBlock
* the engineBlock to set
*/
public void setEngineBlock(EngineBlock engineBlock) {
this.engineBlock = engineBlock;
}
}