diff --git a/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/LdapBaseDAOImpl.java b/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/LdapBaseDAOImpl.java new file mode 100644 index 00000000..ba057450 --- /dev/null +++ b/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/LdapBaseDAOImpl.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2019 GeoSolutions S.A.S. + * http://www.geo-solutions.it + * + * GPLv3 + Classpath exception + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package it.geosolutions.geostore.core.dao.ldap.impl; + +import java.util.List; +import javax.naming.directory.DirContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.ldap.control.SortControlDirContextProcessor; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DirContextProcessor; +import org.springframework.ldap.core.LdapTemplate; +import com.googlecode.genericdao.search.Filter; +import com.googlecode.genericdao.search.ISearch; +import it.geosolutions.geostore.core.dao.ldap.impl.LdapBaseDAOImpl.NullDirContextProcessor; + +public abstract class LdapBaseDAOImpl { + + public static final class NullDirContextProcessor implements DirContextProcessor { + public void postProcess(DirContext ctx) { + // Do nothing + } + + public void preProcess(DirContext ctx) { + // Do nothing + } + } + + protected String searchBase = ""; + protected String baseFilter = "cn=*"; + protected String nameAttribute = "cn"; + protected String descriptionAttribute = "description"; + protected boolean sortEnabled = false; + + protected ContextSource contextSource; + protected LdapTemplate template; + + public LdapBaseDAOImpl(ContextSource contextSource) { + this.contextSource = contextSource; + template = new LdapTemplate(contextSource); + } + + public String getSearchBase() { + return searchBase; + } + + public void setSearchBase(String searchBase) { + this.searchBase = searchBase; + } + + public String getFilter() { + return baseFilter; + } + + public void setFilter(String filter) { + this.baseFilter = filter; + } + + public String getNameAttribute() { + return nameAttribute; + } + + public void setNameAttribute(String nameAttribute) { + this.nameAttribute = nameAttribute; + } + + public String getDescriptionAttribute() { + return descriptionAttribute; + } + + public void setDescriptionAttribute(String descriptionAttribute) { + this.descriptionAttribute = descriptionAttribute; + } + + + protected DirContextProcessor getProcessorForSearch(ISearch search) { + if (sortEnabled && search.getSorts() != null && search.getSorts().size() == 1) { + return new SortControlDirContextProcessor(nameAttribute); + } + return new NullDirContextProcessor(); + } + + public boolean isSortEnabled() { + return sortEnabled; + } + + public void setSortEnabled(boolean sortEnabled) { + this.sortEnabled = sortEnabled; + } + + protected String combineFilters(String baseFilter, String ldapFilter) { + if ("".equals(baseFilter)) { + return ldapFilter; + } + if ("".equals(ldapFilter)) { + return baseFilter; + } + return "(& ("+baseFilter+") ("+ldapFilter+"))"; + } + + protected String getLdapFilter(ISearch search) { + String currentFilter = ""; + for (Filter filter : search.getFilters()) { + currentFilter = combineFilters(currentFilter, getLdapFilter(filter)); + } + return currentFilter; + } + + private String getLdapFilter(Filter filter) { + switch(filter.getOperator()) { + case Filter.OP_EQUAL: + return filter.getProperty() + "=" + filter.getValue().toString(); + //TODO: implement all operators + } + return ""; + } + + protected Expression getSearchExpression(List filters) { + String expression = ""; + for (Filter filter: filters) { + expression = combineExpressions(expression, getSearchExpression(filter)); + } + if ("".equals(expression)) { + expression = "true"; + } + ExpressionParser parser = new SpelExpressionParser(); + return parser.parseExpression(expression); + } + + protected String combineExpressions(String expression, String searchExpression) { + if ("".equals(expression)) { + return searchExpression; + } + if ("".equals(searchExpression)) { + return expression; + } + return "("+expression+") && ("+searchExpression+")"; + } + + private String getSearchExpression(Filter filter) { + switch(filter.getOperator()) { + case Filter.OP_EQUAL: + return filter.getProperty() + "==" + filter.getValue().toString(); + //TODO: implement all operators + } + return ""; + } + +} diff --git a/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/UserDAOImpl.java b/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/UserDAOImpl.java new file mode 100644 index 00000000..7da0193e --- /dev/null +++ b/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/UserDAOImpl.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2019 GeoSolutions S.A.S. + * http://www.geo-solutions.it + * + * GPLv3 + Classpath exception + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package it.geosolutions.geostore.core.dao.ldap.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.naming.directory.SearchControls; +import org.apache.log4j.Logger; +import org.springframework.ldap.control.SortControlDirContextProcessor; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.DirContextProcessor; +import org.springframework.ldap.core.support.AbstractContextMapper; +import org.springframework.transaction.annotation.Transactional; +import com.googlecode.genericdao.search.ISearch; +import it.geosolutions.geostore.core.dao.UserDAO; +import it.geosolutions.geostore.core.model.User; +import it.geosolutions.geostore.core.model.UserAttribute; + +/** + * Class UserDAOImpl. + * + * @author Tobia di Pisa (tobia.dipisa at geo-solutions.it) + * @author ETj (etj at geo-solutions.it) + */ +@Transactional(value = "geostoreTransactionManager") +public class UserDAOImpl extends LdapBaseDAOImpl implements UserDAO { + + private static final Logger LOGGER = Logger.getLogger(UserDAOImpl.class); + + protected Map attributesMapper = new HashMap(); + + public UserDAOImpl(ContextSource contextSource) { + super(contextSource); + } + + public Map getAttributesMapper() { + return attributesMapper; + } + + public void setAttributesMapper(Map attributesMapper) { + this.attributesMapper = attributesMapper; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#persist(T[]) + */ + @Override + public void persist(User... entities) { + + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#findAll() + */ + @Override + public List findAll() { + return ldapSearch(baseFilter, new NullDirContextProcessor()); + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#search(com.trg.search.ISearch) + */ + @SuppressWarnings("unchecked") + @Override + public List search(ISearch search) { + return ldapSearch(combineFilters(baseFilter, getLdapFilter(search)), getProcessorForSearch(search)); + } + + protected List ldapSearch(String filter, DirContextProcessor processor) { + SearchControls controls = new SearchControls(); + controls.setSearchScope(SearchControls.SUBTREE_SCOPE); + return template.search(searchBase, filter, controls, new AbstractContextMapper() { + int counter = 1; + @Override + protected User doMapFromContext(DirContextOperations ctx) { + User user = new User(); + user.setId((long)counter++); + user.setEnabled(true); + user.setName(ctx.getStringAttribute(nameAttribute)); + List attributes = new ArrayList(); + for (String ldapAttr : attributesMapper.keySet()) { + String value = ctx.getStringAttribute(ldapAttr); + String userAttr = attributesMapper.get(ldapAttr); + UserAttribute attr = new UserAttribute(); + attr.setName(userAttr); + attr.setValue(value); + } + user.setAttribute(attributes); + return user; + } + + }, processor); + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#merge(java.lang.Object) + */ + @Override + public User merge(User entity) { + return entity; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#remove(java.lang.Object) + */ + @Override + public boolean remove(User entity) { + return true; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#removeById(java.io.Serializable) + */ + @Override + public boolean removeById(Long id) { + return true; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#find(java.io.Serializable) + */ + @Override + public User find(Long id) { + return null; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#save(T[]) + */ + @Override + public User[] save(User... entities) { + return entities; + } + + @Override + public int count(ISearch search) { + return search(search).size(); + } + +} diff --git a/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/UserGroupDAOImpl.java b/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/UserGroupDAOImpl.java new file mode 100644 index 00000000..56069052 --- /dev/null +++ b/src/core/persistence/src/main/java/it/geosolutions/geostore/core/dao/ldap/impl/UserGroupDAOImpl.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2019 GeoSolutions S.A.S. + * http://www.geo-solutions.it + * + * GPLv3 + Classpath exception + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package it.geosolutions.geostore.core.dao.ldap.impl; + +import java.util.List; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchControls; +import org.apache.log4j.Logger; +import org.springframework.expression.Expression; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.DirContextProcessor; +import org.springframework.ldap.core.support.AbstractContextMapper; +import org.springframework.transaction.annotation.Transactional; +import com.googlecode.genericdao.search.Filter; +import com.googlecode.genericdao.search.ISearch; +import it.geosolutions.geostore.core.dao.UserGroupDAO; +import it.geosolutions.geostore.core.model.UserGroup; +import it.geosolutions.geostore.core.model.enums.GroupReservedNames; + +/** + * Class UserGroupDAOImpl. + * + * @author Tobia di Pisa (tobia.dipisa at geo-solutions.it) + * @author ETj (etj at geo-solutions.it) + */ +@Transactional(value = "geostoreTransactionManager") +public class UserGroupDAOImpl extends LdapBaseDAOImpl implements UserGroupDAO { + + + + private static final Logger LOGGER = Logger.getLogger(UserGroupDAOImpl.class); + + private boolean addEveryOneGroup = false; + + public UserGroupDAOImpl(ContextSource contextSource) { + super(contextSource); + } + + public boolean isAddEveryOneGroup() { + return addEveryOneGroup; + } + + public void setAddEveryOneGroup(boolean addEveryOneGroup) { + this.addEveryOneGroup = addEveryOneGroup; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#persist(T[]) + */ + @Override + public void persist(UserGroup... entities) { + + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#findAll() + */ + @Override + public List findAll() { + return addEveryOne(ldapSearch(baseFilter, new NullDirContextProcessor()), null); + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#find(java.io.Serializable) + */ + @Override + public UserGroup find(Long id) { + return null; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#search(com.trg.search.ISearch) + */ + @SuppressWarnings("unchecked") + @Override + public List search(ISearch search) { + return addEveryOne(ldapSearch(combineFilters(baseFilter, getLdapFilter(search)), getProcessorForSearch(search)), search.getFilters()); + } + + protected List ldapSearch(String filter, DirContextProcessor processor) { + SearchControls controls = new SearchControls(); + controls.setSearchScope(SearchControls.SUBTREE_SCOPE); + return template.search(searchBase, filter, controls, new AbstractContextMapper() { + int counter = 1; + @Override + protected UserGroup doMapFromContext(DirContextOperations ctx) { + UserGroup group = new UserGroup(); + group.setId((long)counter++); + group.setEnabled(true); + group.setGroupName(ctx.getStringAttribute(nameAttribute)); + group.setDescription(ctx.getStringAttribute(descriptionAttribute)); + + return group; + } + + }, processor); + } + + private List addEveryOne(List groups, List filters) { + UserGroup everyoneGroup = new UserGroup(); + everyoneGroup.setGroupName(GroupReservedNames.EVERYONE.groupName()); + everyoneGroup.setId((long)(groups.size() + 1)); + everyoneGroup.setEnabled(true); + if (filters == null || matchFilters(everyoneGroup, filters)) { + boolean everyoneFound = false; + for (UserGroup group : groups) { + if (group.getGroupName().equals(everyoneGroup.getGroupName())) { + everyoneFound = true; + } + } + if (!everyoneFound && addEveryOneGroup) { + groups.add(everyoneGroup); + } + } + return groups; + } + + protected boolean matchFilters(UserGroup group, List filters) { + Expression matchExpression = getSearchExpression(filters); + return matchExpression.getValue(group, Boolean.class); + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#merge(java.lang.Object) + */ + @Override + public UserGroup merge(UserGroup entity) { + return entity; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#remove(java.lang.Object) + */ + @Override + public boolean remove(UserGroup entity) { + return true; + } + + /* + * (non-Javadoc) + * + * @see com.trg.dao.jpa.GenericDAOImpl#removeById(java.io.Serializable) + */ + @Override + public boolean removeById(Long id) { + return true; + } + + @Override + public UserGroup[] save(UserGroup... entities) { + return entities; + } + + @Override + public int count(ISearch search) { + return search(search).size(); + } + +} diff --git a/src/modules/rest/api/src/main/java/it/geosolutions/geostore/services/rest/model/UserGroupList.java b/src/modules/rest/api/src/main/java/it/geosolutions/geostore/services/rest/model/UserGroupList.java index ab5e02ba..578a6333 100644 --- a/src/modules/rest/api/src/main/java/it/geosolutions/geostore/services/rest/model/UserGroupList.java +++ b/src/modules/rest/api/src/main/java/it/geosolutions/geostore/services/rest/model/UserGroupList.java @@ -37,6 +37,7 @@ public class UserGroupList implements Iterable { private List list; public UserGroupList() { + this.list = new ArrayList(); } /**