/** * Licensed to the Austrian Association for Software Tool Integration (AASTI) * under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright * ownership. The AASTI 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 org.openengsb.core.services.internal.security.ldap; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.directory.shared.ldap.model.entry.Entry; import org.apache.directory.shared.ldap.model.name.Dn; import org.openengsb.core.api.security.model.Permission; import org.openengsb.core.api.security.service.NoSuchAttributeException; import org.openengsb.core.api.security.service.NoSuchCredentialsException; import org.openengsb.core.api.security.service.PermissionSetAlreadyExistsException; import org.openengsb.core.api.security.service.PermissionSetNotFoundException; import org.openengsb.core.api.security.service.UserDataManager; import org.openengsb.core.api.security.service.UserExistsException; import org.openengsb.core.api.security.service.UserNotFoundException; import org.openengsb.core.services.internal.security.EntryUtils; import org.openengsb.core.services.internal.security.PermissionUtils; import org.openengsb.core.services.internal.security.model.EntryElement; import org.openengsb.core.services.internal.security.model.EntryValue; import org.openengsb.core.services.internal.security.model.PermissionData; import org.openengsb.core.util.CollectionUtilsExtended; import org.openengsb.infrastructure.ldap.EntryAlreadyExistsException; import org.openengsb.infrastructure.ldap.InconsistentDITException; import org.openengsb.infrastructure.ldap.LdapDao; import org.openengsb.infrastructure.ldap.MissingParentException; import org.openengsb.infrastructure.ldap.NoSuchNodeException; import org.openengsb.infrastructure.ldap.model.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Maps; public class UserDataManagerLdap implements UserDataManager { private LdapDao dao; private static final Logger LOGGER = LoggerFactory.getLogger(UserDataManagerLdap.class); public void setLdapDao(LdapDao dao) { this.dao = dao; } public LdapDao getDao() { return dao; } @Override public String getPermissionSetAttribute(String permissionSet, String attributename) throws PermissionSetNotFoundException, NoSuchAttributeException { Dn dn = SchemaConstants.globalPermissionSetAttribute(permissionSet, attributename); Entry entry; try { entry = dao.lookup(dn); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSet); } catch (NoSuchNodeException e) { throw new NoSuchAttributeException(attributename); } return LdapUtils.extractAttributeEmptyCheck(entry, SchemaConstants.STRING_ATTRIBUTE); } @Override public void setPermissionSetAttribute(String permissionSet, String attributename, String value) throws PermissionSetNotFoundException { Dn parent = SchemaConstants.ouGlobalPermissionSetAttributes(permissionSet); Entry entry = EntryFactory.namedDescriptiveObject(attributename, value, parent); try { dao.storeOverwriteExisting(entry); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSet); } } @Override public Collection<String> getPermissionSetList() { Dn parent = SchemaConstants.ouGlobalPermissionSets(); List<Entry> entries; try { entries = dao.getDirectChildren(parent); } catch (InconsistentDITException e) { throw new LdapRuntimeException(e); } return LdapUtils.extractAttributeEmptyCheck(entries, SchemaConstants.CN_ATTRIBUTE); } @Override public Collection<String> getPermissionSetsFromPermissionSet(String permissionSet) throws PermissionSetNotFoundException { Dn parent = SchemaConstants.ouGlobalPermissionSetChildren(permissionSet); List<Entry> entries; try { entries = dao.getDirectChildren(parent); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSet); } catch (NoSuchNodeException e) { throw new LdapRuntimeException(e); } TimebasedOrderFilter.sortById(entries); return LdapUtils.extractAttributeEmptyCheck(entries, SchemaConstants.CN_ATTRIBUTE); } @Override public Collection<String> getPermissionSetsFromUser(String username) throws UserNotFoundException { Dn parent = SchemaConstants.ouUserPermissionSets(username); List<Entry> entries; try { entries = dao.getDirectChildren(parent); } catch (MissingParentException e) { throw new UserNotFoundException(username); } catch (NoSuchNodeException e) { throw new LdapRuntimeException(e); } TimebasedOrderFilter.sortById(entries); return LdapUtils.extractAttributeEmptyCheck(entries, SchemaConstants.CN_ATTRIBUTE); } @Override public void addPermissionSetToUser(String username, String... permissionSet) throws UserNotFoundException, PermissionSetNotFoundException { Dn parent = SchemaConstants.ouUserPermissionSets(username); try { storePermissionSets(parent, permissionSet); } catch (MissingParentException e) { throw new UserNotFoundException(username); } } @Override public void addPermissionSetToPermissionSet(String permissionSetParent, String... permissionSet) throws PermissionSetNotFoundException { Dn parent = SchemaConstants.ouGlobalPermissionSetChildren(permissionSetParent); try { storePermissionSets(parent, permissionSet); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSetParent); } } private void storePermissionSets(Dn parent, String... permissionSet) throws MissingParentException { for (String s : permissionSet) { if (!dao.exists(SchemaConstants.globalPermissionSet(s))) { throw new PermissionSetNotFoundException(s); } } List<Entry> entries = new LinkedList<Entry>(); for (String s : permissionSet) { // done in separate loop to provide // some atomicity Entry entry = EntryFactory.namedObject(s, parent); TimebasedOrderFilter.addId(entry, false); entries.add(entry); } dao.storeSkipExisting(entries); } @Override public void addPermissionToUser(String username, Permission... permissions) throws UserNotFoundException { Dn parent = SchemaConstants.ouUserPermissionsDirect(username); try { storePermissions(parent, permissions); } catch (MissingParentException e) { throw new UserNotFoundException(username); } catch (EntryAlreadyExistsException e) { throw new LdapRuntimeException(e); //TODO also here duplicates should be allowed but this looks like not } } @Override public void addPermissionToSet(String permissionSet, Permission... permissions) throws PermissionSetNotFoundException { Dn parent = SchemaConstants.ouGlobalPermissionsDirect(permissionSet); try { storePermissions(parent, permissions); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSet); } catch (EntryAlreadyExistsException e) { throw new LdapRuntimeException(e); //TODO here is it possible to store duplicates? think not.. } } @Override public void createPermissionSet(String permissionSet, Permission... permission) throws PermissionSetAlreadyExistsException { List<Entry> permissionSetStructure = EntryFactory.globalPermissionSetStructure(permissionSet); try { dao.store(permissionSetStructure); storePermissions(SchemaConstants.ouGlobalPermissionsDirect(permissionSet), permission); } catch (EntryAlreadyExistsException e) { throw new PermissionSetAlreadyExistsException(); } catch (MissingParentException e) { throw new LdapRuntimeException(e); } } private void storePermissions(Dn parent, Permission... permission) throws EntryAlreadyExistsException, MissingParentException { if (permission == null) { return; } Collection<PermissionData> pd = new LinkedList<PermissionData>(); for (Permission p : permission) { PermissionData data = PermissionUtils.convertPermissionToPermissionData(p); pd.add(data); } List<Entry> permissionStructure = EntryFactory.permissionStructureFromPermissionData(pd, parent); dao.store(permissionStructure); } @Override public void removePermissionFromSet(String permissionSet, Permission... permission) throws PermissionSetNotFoundException { Dn parent = SchemaConstants.ouGlobalPermissionsDirect(permissionSet); try { deletePermission(parent, permission); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSet); } catch (NoSuchNodeException e) { throw new LdapRuntimeException(e); } } @Override public void removePermissionFromUser(String username, Permission... permission) throws UserNotFoundException { Dn parent = SchemaConstants.ouUserPermissionsDirect(username); try { deletePermission(parent, permission); } catch (MissingParentException e) { throw new UserNotFoundException(username); } catch (NoSuchNodeException e) { throw new LdapRuntimeException(e); } } private void deletePermission(Dn parent, Permission... permission) throws MissingParentException, NoSuchNodeException { List<Node> nodes = dao.searchSubtree(parent); Collection<Permission> permissions = extractPermissionsFromNodes(nodes); boolean b = permissions.removeAll(Arrays.asList(permission)); if (b) { dao.deleteSubtreeExcludingRoot(parent); try { storePermissions(parent, permissions.toArray(new Permission[0])); } catch (EntryAlreadyExistsException e) { LOGGER.debug("should never reach here"); throw new LdapRuntimeException(e); } } } @Override public void removePermissionSetFromPermissionSet(String permissionSetParent, String... permissionSet) throws PermissionSetNotFoundException { for (String child : permissionSet) { Dn parent = SchemaConstants.globalPermissionChild(permissionSetParent, child); try { dao.deleteSubtreeIncludingRoot(parent); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSetParent); } catch (NoSuchNodeException e) { LOGGER.warn("permissionSet {} was to be deleted, but not found", child); } } } @Override public void removePermissionSetFromUser(String username, String... permissionSet) throws UserNotFoundException { for (String child : permissionSet) { Dn baseDn = SchemaConstants.userPermissionSet(username, child); try { dao.deleteSubtreeIncludingRoot(baseDn); } catch (MissingParentException e) { throw new UserNotFoundException(username); } catch (NoSuchNodeException e) { LOGGER.warn("permissionSet {} was to be deleted, but not found", child); } } } @Override public Collection<Permission> getPermissionsForUser(String username) throws UserNotFoundException { List<Node> nodes; try { nodes = dao.searchSubtree(SchemaConstants.ouUserPermissionsDirect(username)); } catch (MissingParentException e) { throw new UserNotFoundException(); } catch (NoSuchNodeException e) { throw new LdapRuntimeException(e); } return extractPermissionsFromNodes(nodes); } private Collection<Permission> extractPermissionsFromNodes(List<Node> nodes) { Collection<PermissionData> permissionData = new LinkedList<PermissionData>(); TimebasedOrderFilter.sortByIdNode(nodes); for (Node permission : nodes) { Map<String, EntryValue> attributes = Maps.newHashMap(); for (Node property : permission.getChildren()) { List<EntryElement> entryElements = new LinkedList<EntryElement>(); TimebasedOrderFilter.sortByIdNode(property.getChildren()); for (Node propertyValue : property.getChildren()) { EntryElement entryElement = new EntryElement(); entryElement.setType(LdapUtils.extractAttributeEmptyCheck(propertyValue.getEntry(), SchemaConstants.JAVA_CLASS_NAME_ATTRIBUTE)); entryElement.setValue(LdapUtils.extractAttributeEmptyCheck(propertyValue.getEntry(), SchemaConstants.STRING_ATTRIBUTE)); entryElements.add(entryElement); } String key = LdapUtils.extractAttributeEmptyCheck(property.getEntry(), SchemaConstants.CN_ATTRIBUTE); EntryValue entryValue = new EntryValue(key, entryElements); attributes.put(key, entryValue); // TODO why need key 2x? } String type = LdapUtils.extractAttributeEmptyCheck(permission.getEntry(), SchemaConstants.JAVA_CLASS_NAME_ATTRIBUTE); PermissionData data = new PermissionData(); data.setType(type); data.setAttributes(attributes); permissionData.add(data); } return EntryUtils.convertAllBeanDataToObjects(permissionData); } @Override public <T extends Permission> Collection<T> getPermissionsForUser(String username, Class<T> type) throws UserNotFoundException { // TODO improve performance by better query return CollectionUtilsExtended.filterCollectionByClass(getPermissionsForUser(username), type); } @Override public Collection<Permission> getPermissionsFromPermissionSet(String permissionSet) throws PermissionSetNotFoundException { List<Node> nodes; try { nodes = dao.searchSubtree(SchemaConstants.ouGlobalPermissionsDirect(permissionSet)); } catch (MissingParentException e) { throw new PermissionSetNotFoundException(permissionSet); } catch (NoSuchNodeException e) { throw new LdapRuntimeException(e); } return extractPermissionsFromNodes(nodes); } @Override public Collection<Permission> getAllPermissionsForUser(String username) throws UserNotFoundException { Collection<Permission> result = new HashSet<Permission>(); result.addAll(getPermissionsForUser(username)); for (String s : getPermissionSetsFromUser(username)) { result.addAll(getAllPermissionsFromPermissionSet(s)); } return result; } @Override public <T extends Permission> Collection<T> getAllPermissionsForUser(String username, Class<T> type) throws UserNotFoundException { // TODO improve performance by better query return CollectionUtilsExtended.filterCollectionByClass(getPermissionsForUser(username), type); } // TODO note: this does not reflect insertion order because HashSet is used @Override public Collection<Permission> getAllPermissionsFromPermissionSet(String permissionSet) throws PermissionSetNotFoundException { Collection<Permission> result = new HashSet<Permission>(); for (String s : getAllPermissionSetsFromPermissionSet(permissionSet)) { result.addAll(getPermissionsFromPermissionSet(s)); } return result; } private Collection<String> getAllPermissionSetsFromPermissionSet(String permissionSet) { Collection<String> result = new HashSet<String>(); for (String s : getPermissionSetsFromPermissionSet(permissionSet)) { boolean b = result.addAll(getAllPermissionSetsFromPermissionSet(s)); if (!b) { // prevents circles break; } } return result; } @Override public Collection<String> getUserList() { List<Entry> entries; try { entries = dao.getDirectChildren(SchemaConstants.ouUsers()); } catch (NoSuchNodeException e) { throw new LdapRuntimeException(e); } catch (MissingParentException e) { throw new LdapRuntimeException(e); } return LdapUtils.extractAttributeEmptyCheck(entries, SchemaConstants.CN_ATTRIBUTE); } @Override public void createUser(String username) throws UserExistsException { List<Entry> userStructure = userStructure(username); try { dao.store(userStructure); } catch (EntryAlreadyExistsException e) { throw new UserExistsException(); } catch (MissingParentException e) { throw new LdapRuntimeException(e); } } @Override public void deleteUser(String username) { try { dao.deleteSubtreeIncludingRoot(SchemaConstants.user(username)); } catch (NoSuchNodeException e) { LOGGER.warn("user {} was to be deleted, but not found", username); } catch (MissingParentException e) { throw new LdapRuntimeException(e); } } @Override public List<Object> getUserAttribute(String username, String attributename) throws UserNotFoundException, NoSuchAttributeException { List<Entry> entries; try { entries = dao.getDirectChildren(SchemaConstants.userAttribute(username, attributename)); } catch (MissingParentException e) { throw new UserNotFoundException(); } catch (NoSuchNodeException e) { throw new NoSuchAttributeException(); } TimebasedOrderFilter.sortById(entries); return extractUserAttributeValues(entries); } private List<Object> extractUserAttributeValues(List<Entry> entries) { List<EntryElement> entryElements = new LinkedList<EntryElement>(); for (Entry entry : entries) { String type = LdapUtils.extractAttributeEmptyCheck(entry, SchemaConstants.JAVA_CLASS_NAME_ATTRIBUTE); String value = LdapUtils.extractAttributeEmptyCheck(entry, SchemaConstants.STRING_ATTRIBUTE); entryElements.add(new EntryElement(type, value)); } return EntryUtils.convertAllEntryElementsToObject(entryElements); } @Override public void setUserAttribute(String username, String attributename, Object... value) throws UserNotFoundException { Entry attribute = EntryFactory.namedObject(attributename, SchemaConstants.ouUserAttributes(username)); List<Entry> attributeValues = new LinkedList<Entry>(); for (EntryElement e : EntryUtils.makeEntryElementList(value)) { Entry entry = EntryFactory.javaObject(e.getType(), e.getValue(), attribute.getDn()); attributeValues.add(entry); } TimebasedOrderFilter.addIds(attributeValues, true); try { dao.storeOverwriteExisting(attribute); for (Entry entry : attributeValues) { dao.storeSkipExisting(entry); } } catch (MissingParentException e) { throw new UserNotFoundException(username); } } @Override public void removeUserAttribute(String username, String attributename) throws UserNotFoundException { try { dao.deleteSubtreeIncludingRoot(SchemaConstants.userAttribute(username, attributename)); } catch (MissingParentException e) { throw new UserNotFoundException(); } catch (NoSuchNodeException e) { LOGGER.warn("attribute {} was to be deleted, but not found", attributename); } } @Override public void removeUserCredentials(String username, String credentials) throws UserNotFoundException { try { dao.deleteSubtreeIncludingRoot(SchemaConstants.userCredentials(username, credentials)); } catch (MissingParentException e) { throw new UserNotFoundException(); } catch (NoSuchNodeException e) { LOGGER.warn("credentials {} was to be deleted, but not found", credentials); } } @Override public void setUserCredentials(String username, String credentialsType, String credentialsValue) throws UserNotFoundException { Dn parent = SchemaConstants.ouUserCredentials(username); Entry entry = EntryFactory.namedDescriptiveObject(credentialsType, credentialsValue, parent); try { dao.storeOverwriteExisting(entry); } catch (MissingParentException e) { throw new UserNotFoundException(); } } @Override public String getUserCredentials(String username, String credentials) throws UserNotFoundException, NoSuchCredentialsException { try { Entry entry = dao.lookup(SchemaConstants.userCredentials(username, credentials)); return LdapUtils.extractAttributeEmptyCheck(entry, SchemaConstants.STRING_ATTRIBUTE); } catch (MissingParentException e) { throw new UserNotFoundException(); } catch (NoSuchNodeException e) { throw new NoSuchCredentialsException(); } } private List<Entry> userStructure(String username) { Entry entry = EntryFactory.namedObject(username, SchemaConstants.ouUsers()); Entry ouPermissions = EntryFactory.organizationalUnit("permissions", entry.getDn()); Entry ouDirectPermissions = EntryFactory.organizationalUnit("direct", ouPermissions.getDn()); Entry ouPermissionSets = EntryFactory.organizationalUnit("permissionSets", ouPermissions.getDn()); Entry ouCredentials = EntryFactory.organizationalUnit("credentials", entry.getDn()); Entry ouAttributes = EntryFactory.organizationalUnit("attributes", entry.getDn()); return Arrays.asList(entry, ouPermissions, ouDirectPermissions, ouPermissionSets, ouCredentials, ouAttributes); } }