From f29d896c42c3e7a841ca731a4b4e860a92ac5b8c Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Tue, 14 Oct 2014 13:40:56 +0200 Subject: [PATCH] OO-1249: implements 2 security callbacks for question pool --- .../site/ui/_i18n/LocalStrings_de.properties | 2 + .../gui/control/_spring/sitedefContext.xml | 10 +++ .../org/olat/modules/qpool/QPoolService.java | 3 + .../olat/modules/qpool/manager/PoolDAO.java | 30 ++++++++ .../manager/QuestionPoolServiceImpl.java | 6 ++ .../olat/modules/qpool/model/PoolImpl.java | 4 +- ...AndPoolPrivateMembersSecurityCallback.java | 74 ++++++++++++++++++ .../PoolPrivateMembersSecurityCallback.java | 77 +++++++++++++++++++ .../modules/qpool/manager/PoolDAOTest.java | 59 ++++++++++++++ 9 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/olat/modules/qpool/site/AuthorAndPoolPrivateMembersSecurityCallback.java create mode 100644 src/main/java/org/olat/modules/qpool/site/PoolPrivateMembersSecurityCallback.java diff --git a/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties index 3566b007c0d..3e3306ef634 100644 --- a/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties @@ -46,3 +46,5 @@ restrictToInstResourceManagersAndAuthorsSiteSecurityCallback=Autoren und Lernres restrictToUserManagerSiteSecurityCallback=Benutzerverwalter restrictToGroupManagerSiteSecurityCallback=Gruppenverwalter restrictToPoolAdminSiteSecurityCallback=Poolverwalter +poolPrivateMembersSiteSecurityCallback=Poolmitglieder und Poolverwalter +authorAndPoolPrivateMembersSiteSecurityCallback=Autoren, Poolmitglieder und Poolverwalter diff --git a/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml b/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml index bff5af93690..36537288afa 100644 --- a/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml +++ b/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml @@ -143,6 +143,16 @@ <property name="catalogManager" ref="catalogManager" /> </bean> + <bean id="poolPrivateMembersSiteSecurityCallback" class="org.olat.modules.qpool.site.PoolPrivateMembersSecurityCallback"> + <property name="qPoolService" ref="qpoolService" /> + <property name="questionPoolModule" ref="qpoolModule" /> + </bean> + + <bean id="authorAndPoolPrivateMembersSiteSecurityCallback" class="org.olat.modules.qpool.site.AuthorAndPoolPrivateMembersSecurityCallback"> + <property name="qPoolService" ref="qpoolService" /> + <property name="questionPoolModule" ref="qpoolModule" /> + </bean> + <!-- Alternative controllers --> <bean id="courseSiteForbiddenAlt" class="org.olat.core.gui.control.navigation.SiteAlternativeControllerCreator"> diff --git a/src/main/java/org/olat/modules/qpool/QPoolService.java b/src/main/java/org/olat/modules/qpool/QPoolService.java index c20094e7ad4..c4a97b8e8f3 100644 --- a/src/main/java/org/olat/modules/qpool/QPoolService.java +++ b/src/main/java/org/olat/modules/qpool/QPoolService.java @@ -25,6 +25,7 @@ import java.util.Locale; import java.util.Set; import java.util.zip.ZipOutputStream; +import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.media.MediaResource; @@ -108,6 +109,8 @@ public interface QPoolService { //pools public List<Pool> getPools(Identity identity, Roles roles); + public boolean isMemberOfPrivatePools(IdentityRef identity); + public boolean isOwner(Identity owner, Pool pool); public void addOwners(List<Identity> owners, List<Pool> pools); diff --git a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java index 922d786d4f5..25168da2e08 100644 --- a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java @@ -26,6 +26,8 @@ import java.util.List; import javax.persistence.TypedQuery; import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.GroupRoles; +import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.SecurityGroup; import org.olat.basesecurity.SecurityGroupMembershipImpl; import org.olat.core.commons.persistence.DB; @@ -144,6 +146,34 @@ public class PoolDAO { return query.getResultList(); } + public boolean isMemberOfPrivatePools(IdentityRef identity) { + StringBuilder sb = new StringBuilder(); + sb.append("select count(pool.key) from qpool pool") + .append(" where exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember ") + .append(" where vmember.identity.key=:identityKey and vmember.securityGroup=pool.ownerGroup)"); + + Number countPool = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Number.class) + .setParameter("identityKey", identity.getKey()) + .getSingleResult(); + Number countShared = null; + if(countPool == null || countPool.intValue() <= 0) { + StringBuilder sc = new StringBuilder(); + sc.append("select count(bgi.key) from ").append(org.olat.group.BusinessGroupImpl.class.getName()).append(" as bgi ") + .append(" inner join bgi.baseGroup as baseGroup") + .append(" inner join baseGroup.members as membership") + .append(" where membership.identity.key=:identityKey") + .append(" and membership.role in ('").append(GroupRoles.coach.name()).append("','").append(GroupRoles.participant.name()).append("')") + .append(" and exists (select share from qshareitem share where share.resource=bgi.resource)"); + + countShared = dbInstance.getCurrentEntityManager() + .createQuery(sc.toString(), Number.class) + .setParameter("identityKey", identity.getKey()) + .getSingleResult(); + } + return (countPool != null && countPool.intValue() > 0) || (countShared != null && countShared.intValue() > 0); + } + public List<Pool> getPools(Identity identity, int firstResult, int maxResults) { StringBuilder sb = new StringBuilder(); sb.append("select pool from qpool pool") diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java index 8b960b1f7b7..dc708a6c1d9 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.zip.ZipOutputStream; import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.SecurityGroup; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DefaultResultInfos; @@ -320,6 +321,11 @@ public class QuestionPoolServiceImpl implements QPoolService { } return poolDao.getPools(identity, 0, -1); } + + @Override + public boolean isMemberOfPrivatePools(IdentityRef identity) { + return poolDao.isMemberOfPrivatePools(identity); + } @Override public List<QuestionItem2Pool> getPoolInfosByItem(QuestionItemShort item) { diff --git a/src/main/java/org/olat/modules/qpool/model/PoolImpl.java b/src/main/java/org/olat/modules/qpool/model/PoolImpl.java index 3a2d4f1a15a..6cd850553d2 100644 --- a/src/main/java/org/olat/modules/qpool/model/PoolImpl.java +++ b/src/main/java/org/olat/modules/qpool/model/PoolImpl.java @@ -58,8 +58,8 @@ public class PoolImpl implements Pool, CreateInfo, ModifiedInfo, Persistable { private static final long serialVersionUID = 581458115174074849L; @Id - @GeneratedValue(generator = "system-uuid") - @GenericGenerator(name = "system-uuid", strategy = "hilo") + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) private Long key; diff --git a/src/main/java/org/olat/modules/qpool/site/AuthorAndPoolPrivateMembersSecurityCallback.java b/src/main/java/org/olat/modules/qpool/site/AuthorAndPoolPrivateMembersSecurityCallback.java new file mode 100644 index 00000000000..d7e696b4547 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/site/AuthorAndPoolPrivateMembersSecurityCallback.java @@ -0,0 +1,74 @@ +/** + * OLAT - Online Learning and Training<br> + * http://www.olat.org + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Copyright (c) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ +package org.olat.modules.qpool.site; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.navigation.SiteSecurityCallback; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionPoolModule; + +/** + * + * Initial date: 14.10.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AuthorAndPoolPrivateMembersSecurityCallback implements SiteSecurityCallback { + + private QPoolService qPoolService; + private QuestionPoolModule questionPoolModule; + + /** + * [used by Spring] + * @param qPoolService + */ + public void setQPoolService(QPoolService qPoolService) { + this.qPoolService = qPoolService; + } + + /** + * [used by Spring] + * @param questionPoolModule + */ + public void setQuestionPoolModule(QuestionPoolModule questionPoolModule) { + this.questionPoolModule = questionPoolModule; + } + + /** + * @see com.frentix.olat.coursesite.SiteSecurityCallback#isAllowedToLaunchSite(org.olat.core.gui.UserRequest) + */ + @Override + public boolean isAllowedToLaunchSite(UserRequest ureq) { + if (!questionPoolModule.isEnabled() || ureq == null || ureq.getUserSession() == null || ureq.getUserSession().getRoles() == null + || ureq.getIdentity() == null + || ureq.getUserSession().getRoles().isInvitee() || ureq.getUserSession().getRoles().isGuestOnly()) { + return false; + } + Roles roles = ureq.getUserSession().getRoles(); + if (roles.isOLATAdmin() || roles.isPoolAdmin() || roles.isAuthor()) { + return true; + } + Identity identity = ureq.getIdentity(); + return qPoolService.isMemberOfPrivatePools(identity); + } +} diff --git a/src/main/java/org/olat/modules/qpool/site/PoolPrivateMembersSecurityCallback.java b/src/main/java/org/olat/modules/qpool/site/PoolPrivateMembersSecurityCallback.java new file mode 100644 index 00000000000..27f798a5f61 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/site/PoolPrivateMembersSecurityCallback.java @@ -0,0 +1,77 @@ +/** + * OLAT - Online Learning and Training<br> + * http://www.olat.org + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Copyright (c) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ +package org.olat.modules.qpool.site; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.navigation.SiteSecurityCallback; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionPoolModule; + +/** + * + * Initial date: 14.10.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class PoolPrivateMembersSecurityCallback implements SiteSecurityCallback { + + private QPoolService qPoolService; + private QuestionPoolModule questionPoolModule; + + + /** + * [used by Spring] + * @param qPoolService + */ + public void setQPoolService(QPoolService qPoolService) { + this.qPoolService = qPoolService; + } + + /** + * [used by Spring] + * @param questionPoolModule + */ + public void setQuestionPoolModule(QuestionPoolModule questionPoolModule) { + this.questionPoolModule = questionPoolModule; + } + + /** + * @see com.frentix.olat.coursesite.SiteSecurityCallback#isAllowedToLaunchSite(org.olat.core.gui.UserRequest) + */ + @Override + public boolean isAllowedToLaunchSite(UserRequest ureq) { + if (!questionPoolModule.isEnabled() || ureq == null || ureq.getUserSession() == null || ureq.getUserSession().getRoles() == null + || ureq.getIdentity() == null + || ureq.getUserSession().getRoles().isInvitee() || ureq.getUserSession().getRoles().isGuestOnly()) { + return false; + } + + Roles roles = ureq.getUserSession().getRoles(); + if (roles.isOLATAdmin() || roles.isPoolAdmin()) { + return true; + } + + Identity identity = ureq.getIdentity(); + return qPoolService.isMemberOfPrivatePools(identity); + } +} diff --git a/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java index b7cc38a1ec9..8c1dcfb6e66 100644 --- a/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java @@ -28,8 +28,12 @@ import java.util.UUID; import junit.framework.Assert; import org.junit.Test; +import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.group.BusinessGroup; +import org.olat.group.manager.BusinessGroupDAO; +import org.olat.group.manager.BusinessGroupRelationDAO; import org.olat.ims.qti.QTIConstants; import org.olat.modules.qpool.Pool; import org.olat.modules.qpool.QuestionItem; @@ -58,9 +62,15 @@ public class PoolDAOTest extends OlatTestCase { @Autowired private QItemTypeDAO qItemTypeDao; @Autowired + private QuestionItemDAO questionDao; + @Autowired private QItemQueriesDAO qItemQueriesDao; @Autowired private QuestionItemDAO questionItemDao; + @Autowired + private BusinessGroupDAO businessGroupDao; + @Autowired + private BusinessGroupRelationDAO businessGroupRelationDao; @Test public void createPool() { @@ -126,6 +136,55 @@ public class PoolDAOTest extends OlatTestCase { Assert.assertFalse(quidamPoolList.contains(pool)); } + @Test + public void isMemberOfPrivatePools_poolOnly() { + Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Pool-owner-" + UUID.randomUUID().toString()); + Pool pool = poolDao.createPool(id, "NGC owned", false); + Assert.assertNotNull(pool); + dbInstance.commitAndCloseSession(); + + boolean isMember = poolDao.isMemberOfPrivatePools(id); + Assert.assertTrue(isMember); + } + + @Test + public void isMemberOfPrivatePools_groupOnly() { + Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("Group-owner-" + UUID.randomUUID().toString()); + Identity participant = JunitTestHelper.createAndPersistIdentityAsUser("Group-participant-" + UUID.randomUUID().toString()); + //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + BusinessGroup group = businessGroupDao.createAndPersist(owner, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); + QuestionItem item = questionDao.createAndPersist(owner, "Shared-Item-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + questionDao.share(item, group.getResource()); + + businessGroupRelationDao.addRole(participant, group, GroupRoles.participant.name()); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(item); + Assert.assertNotNull(group); + + //retrieve them + boolean isOwnerMember = poolDao.isMemberOfPrivatePools(owner); + Assert.assertTrue(isOwnerMember); + boolean isParticipantMember = poolDao.isMemberOfPrivatePools(participant); + Assert.assertTrue(isParticipantMember); + } + + @Test + public void isMemberOfPrivatePools_negativeTest() { + Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("Pool-owner-" + UUID.randomUUID().toString()); + Identity somebody = JunitTestHelper.createAndPersistIdentityAsUser("Somebody-" + UUID.randomUUID().toString()); + //pool + Pool pool = poolDao.createPool(owner, "NGC owned", false); + Assert.assertNotNull(pool); + //group without item + BusinessGroup group = businessGroupDao.createAndPersist(owner, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); + businessGroupRelationDao.addRole(somebody, group, GroupRoles.participant.name()); + dbInstance.commitAndCloseSession(); + + boolean isMember = poolDao.isMemberOfPrivatePools(somebody); + Assert.assertFalse(isMember); + } + @Test public void addItemToPool() { //create a pool -- GitLab