Skip to content

Commit dad59c0

Browse files
committed
Merge branch 'hotfix/2021.1.4' into stable-2021.1
2 parents 94de657 + 35fb49c commit dad59c0

File tree

12 files changed

+135
-11
lines changed

12 files changed

+135
-11
lines changed

Source/Plugins/Core/com.equella.core/scalasrc/com/tle/core/security/AclChecks.scala

+22
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.tle.common.security.SecurityConstants
2525
import com.tle.common.security.SecurityConstants.GRANT
2626
import com.tle.core.db.{DB, UserContext}
2727
import com.tle.exceptions.PrivilegeRequiredException
28+
import com.tle.legacy.LegacyGuice
2829
import io.doolse.simpledba.jdbc._
2930

3031
import scala.collection.JavaConverters._
@@ -107,4 +108,25 @@ object AclChecks {
107108
}
108109
}
109110

111+
/**
112+
* Checks if the current user has the specified ACL.
113+
*
114+
* @param privilege Required ACL, typically defined as a constant in `com.tle.common.security.SecurityConstants`
115+
* @param includePossibleOwnerAcls `true` to include possible owner ACLs
116+
*/
117+
def hasAcl(privilege: String, includePossibleOwnerAcls: Boolean = false): Boolean = {
118+
LegacyGuice.aclManager.hasPrivilege(Set(privilege).asJava, includePossibleOwnerAcls)
119+
}
120+
121+
/**
122+
* Checks if the current user has the specified ACL or throws `PrivilegeRequiredException`.
123+
*
124+
* @param privilege Required ACL, typically defined as a constant in `com.tle.common.security.SecurityConstants`
125+
* @param includePossibleOwnerAcls `true` to include possible owner ACLs
126+
*/
127+
def hasAclOrThrow(privilege: String, includePossibleOwnerAcls: Boolean = false): Unit = {
128+
if (!hasAcl(privilege, includePossibleOwnerAcls)) {
129+
throw new PrivilegeRequiredException(privilege)
130+
}
131+
}
110132
}

Source/Plugins/Core/com.equella.core/scalasrc/com/tle/web/api/search/SearchHelper.scala

+39-7
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ object SearchHelper {
278278
beans.asScala
279279
// Filter out restricted attachments if the user does not have permissions to view them
280280
.filter(a => !a.isRestricted || hasRestrictedAttachmentPrivileges)
281+
.map(sanitiseAttachmentBean)
281282
.map(att => {
282283
val broken =
283284
recurseBrokenAttachmentCheck(
@@ -317,21 +318,33 @@ object SearchHelper {
317318
}
318319
}
319320

321+
/**
322+
* Find out the latest version of the Item which a Custom Attachment points to.
323+
*
324+
* @param version Version of a linked Item. It is either 0 or 1 where 0 means using the latest version
325+
* and 1 means always using version 1.
326+
* @param uuid UUID of the linked Item.
327+
*/
328+
def getLatestVersionForCustomAttachment(version: Int, uuid: String): Int = {
329+
version match {
330+
// If version of is 0, find the real latest version of this Item.
331+
case 0 => LegacyGuice.itemService.getLatestVersion(uuid)
332+
case realVersion => realVersion
333+
}
334+
}
335+
320336
/**
321337
* Determines if a given customAttachment is invalid. Required as these attachments can be recursive.
322338
* @param customAttachment The attachment to check.
323339
* @return If true, this attachment is broken.
324340
*/
325341
def getBrokenAttachmentStatusForResourceAttachment(
326342
customAttachment: CustomAttachment): Boolean = {
327-
val uuid = customAttachment.getData("uuid").asInstanceOf[String]
328-
// If version of the linked Item is 0, find the latest version of this Item.
329-
val version = customAttachment.getData("version").asInstanceOf[Int] match {
330-
case 0 => LegacyGuice.itemService.getLatestVersion(uuid)
331-
case realVersion => realVersion
332-
}
343+
val uuid = customAttachment.getData("uuid").asInstanceOf[String]
344+
val version = customAttachment.getData("version").asInstanceOf[Int]
345+
346+
val key = new ItemId(uuid, getLatestVersionForCustomAttachment(version, uuid))
333347

334-
val key = new ItemId(uuid, version)
335348
if (customAttachment.getType != "resource") {
336349
return false;
337350
}
@@ -438,4 +451,23 @@ object SearchHelper {
438451
*/
439452
def isLatestVersion(itemID: ItemIdKey): Boolean =
440453
itemID.getVersion == LegacyGuice.itemService.getLatestVersion(itemID.getUuid)
454+
455+
/**
456+
* When an AttachmentBean is converted to SearchResultAttachment, it may require some extra sanitising
457+
* to complete the conversion. The sanitising work includes tasks listed below.
458+
*
459+
* 1. Help ResourceAttachmentBean check the version of its linked resource.
460+
*
461+
* @param att An AttachmentBean to be sanitised.
462+
*/
463+
def sanitiseAttachmentBean(att: AttachmentBean): AttachmentBean = {
464+
att match {
465+
case bean: ResourceAttachmentBean =>
466+
val latestVersion =
467+
getLatestVersionForCustomAttachment(bean.getItemVersion, bean.getItemUuid)
468+
bean.setItemVersion(latestVersion)
469+
case _ =>
470+
}
471+
att
472+
}
441473
}

Source/Plugins/Core/com.equella.core/scalasrc/com/tle/web/api/users/UserQueryResource.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ package com.tle.web.api.users
2121
import com.tle.beans.usermanagement.standard.wrapper.SharedSecretSettings
2222
import com.tle.common.security.SecurityConstants
2323
import com.tle.common.usermanagement.user.valuebean.{GroupBean, RoleBean, UserBean}
24+
import com.tle.core.security.AclChecks.hasAclOrThrow
2425
import com.tle.legacy.LegacyGuice
2526
import io.swagger.annotations.{Api, ApiParam}
2627
import javax.ws.rs._
27-
2828
import scala.collection.JavaConverters._
2929

3030
case class LookupQuery(users: Seq[String], groups: Seq[String], roles: Seq[String])
@@ -55,6 +55,7 @@ class UserQueryResource {
5555
@POST
5656
@Path("lookup")
5757
def lookup(queries: LookupQuery): LookupQueryResult = {
58+
hasAclOrThrow(SecurityConstants.LIST_USERS)
5859
val us = LegacyGuice.userService
5960
val users = us.getInformationForUsers(queries.users.asJava)
6061
val groups = us.getInformationForGroups(queries.groups.asJava)
@@ -72,6 +73,7 @@ class UserQueryResource {
7273
@QueryParam("groups") @DefaultValue("true") @ApiParam("Include groups") sgroups: Boolean,
7374
@QueryParam("roles") @DefaultValue("true") @ApiParam("Include roles") sroles: Boolean)
7475
: LookupQueryResult = {
76+
hasAclOrThrow(SecurityConstants.LIST_USERS)
7577
val us = LegacyGuice.userService
7678
val users = if (susers) us.searchUsers(q).asScala else Iterable.empty
7779
val groups = if (sgroups) us.searchGroups(q).asScala else Iterable.empty

Source/Plugins/Security/com.tle.core.security/src/com/tle/core/security/TLEAclManager.java

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ <T> Collection<T> filterNonGrantedObjects(
4949
*/
5050
boolean hasPrivilege(Object domainObj, Privilege... privilege);
5151

52+
/**
53+
* Check if user has the supplied privileges for any object.
54+
*
55+
* @param privileges List of privileges to be checked
56+
* @param includePossibleOwnerAcls true to include 'ownerAcl'.
57+
* @return true if ANY of the supplied privileges are granted.
58+
*/
59+
boolean hasPrivilege(Collection<String> privileges, boolean includePossibleOwnerAcls);
60+
5261
/** Return a map of domain objects to maps of privileges. */
5362
<T> Map<T, Map<String, Boolean>> getPrivilegesForObjects(
5463
Collection<String> privileges, Collection<T> domainObjs);

Source/Plugins/Security/com.tle.core.security/src/com/tle/core/security/impl/TLEAclManagerImpl.java

+5
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ public boolean hasPrivilege(Object domainObj, Privilege... privilege) {
164164
return !filterNonGrantedPrivileges(domainObj, privs).isEmpty();
165165
}
166166

167+
@Override
168+
public boolean hasPrivilege(Collection<String> privileges, boolean includePossibleOwnerAcls) {
169+
return !filterNonGrantedPrivileges(privileges, includePossibleOwnerAcls).isEmpty();
170+
}
171+
167172
@Override
168173
@Transactional
169174
public <T> Map<T, Map<String, Boolean>> getPrivilegesForObjects(

autotest/Tests/tests/facet/institution/acls/entries.xml

+13
Original file line numberDiff line numberDiff line change
@@ -1910,4 +1910,17 @@
19101910
<aclOrder>0</aclOrder>
19111911
<aclPriority>-1900</aclPriority>
19121912
</com.tle.beans.security.AccessEntry>
1913+
<com.tle.beans.security.AccessEntry>
1914+
<id>36596</id>
1915+
<expression>
1916+
<id>36595</id>
1917+
<dynamic>false</dynamic>
1918+
</expression>
1919+
<targetObject>*</targetObject>
1920+
<privilege>LIST_USERS</privilege>
1921+
<aggregateOrdering>0100 0000 G</aggregateOrdering>
1922+
<grantRevoke>G</grantRevoke>
1923+
<aclOrder>0</aclOrder>
1924+
<aclPriority>-1900</aclPriority>
1925+
</com.tle.beans.security.AccessEntry>
19131926
</list>

autotest/Tests/tests/facet/institution/acls/expressions.xml

+5
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,9 @@
5454
<dynamic>false</dynamic>
5555
<expression>U:f40e91d5-2024-4bb0-87d6-1a0fa22ebae5 </expression>
5656
</com.tle.beans.security.AccessExpression>
57+
<com.tle.beans.security.AccessExpression>
58+
<id>36595</id>
59+
<dynamic>false</dynamic>
60+
<expression>U:f40e91d5-2024-4bb0-87d6-1a0fa22ebae5 R:351c2f38-b78a-4049-88d5-dc33693c9a9f OR </expression>
61+
</com.tle.beans.security.AccessExpression>
5762
</list>

autotest/Tests/tests/rest/institution/acls/entries.xml

+13
Original file line numberDiff line numberDiff line change
@@ -1767,4 +1767,17 @@
17671767
<aclOrder>1</aclOrder>
17681768
<aclPriority>0</aclPriority>
17691769
</com.tle.beans.security.AccessEntry>
1770+
<com.tle.beans.security.AccessEntry>
1771+
<id>37230</id>
1772+
<expression>
1773+
<id>37229</id>
1774+
<dynamic>false</dynamic>
1775+
</expression>
1776+
<targetObject>*</targetObject>
1777+
<privilege>LIST_USERS</privilege>
1778+
<aggregateOrdering>0100 0000 G</aggregateOrdering>
1779+
<grantRevoke>G</grantRevoke>
1780+
<aclOrder>0</aclOrder>
1781+
<aclPriority>-1900</aclPriority>
1782+
</com.tle.beans.security.AccessEntry>
17701783
</list>

autotest/Tests/tests/rest/institution/acls/expressions.xml

+5
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,9 @@
4444
<dynamic>false</dynamic>
4545
<expression>U:adfcaf58-241b-4eca-9740-6a26d1c3dd58 </expression>
4646
</com.tle.beans.security.AccessExpression>
47+
<com.tle.beans.security.AccessExpression>
48+
<id>37229</id>
49+
<dynamic>false</dynamic>
50+
<expression>U:adfcaf58-241b-4eca-9740-6a26d1c3dd58 </expression>
51+
</com.tle.beans.security.AccessExpression>
4752
</list>

autotest/Tests/tests/vanilla/institution/acls/entries.xml

+14-1
Original file line numberDiff line numberDiff line change
@@ -3600,4 +3600,17 @@
36003600
<aclOrder>0</aclOrder>
36013601
<aclPriority>-1400</aclPriority>
36023602
</com.tle.beans.security.AccessEntry>
3603-
</list>
3603+
<com.tle.beans.security.AccessEntry>
3604+
<id>33573</id>
3605+
<expression>
3606+
<id>33572</id>
3607+
<dynamic>false</dynamic>
3608+
</expression>
3609+
<targetObject>*</targetObject>
3610+
<privilege>LIST_USERS</privilege>
3611+
<aggregateOrdering>0100 0000 G</aggregateOrdering>
3612+
<grantRevoke>G</grantRevoke>
3613+
<aclOrder>0</aclOrder>
3614+
<aclPriority>-1900</aclPriority>
3615+
</com.tle.beans.security.AccessEntry>
3616+
</list>

autotest/Tests/tests/vanilla/institution/acls/expressions.xml

+6-1
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,9 @@
114114
<dynamic>false</dynamic>
115115
<expression>U:f2ce5cf5-e6d2-8d1a-4627-4e917b4e6ba3</expression>
116116
</com.tle.beans.security.AccessExpression>
117-
</list>
117+
<com.tle.beans.security.AccessExpression>
118+
<id>33572</id>
119+
<dynamic>false</dynamic>
120+
<expression>U:b09a4042-b091-87ed-eba9-6fb3c0fbe9a6 R:ROLE_SYSTEM_ADMINISTRATOR OR </expression>
121+
</com.tle.beans.security.AccessExpression>
122+
</list>

build.sbt

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ name := "Equella"
116116

117117
equellaMajor in ThisBuild := 2021
118118
equellaMinor in ThisBuild := 1
119-
equellaPatch in ThisBuild := 3
119+
equellaPatch in ThisBuild := 4
120120
equellaStream in ThisBuild := "Stable"
121121
equellaBuild in ThisBuild := buildConfig.value.getString("build.buildname")
122122

0 commit comments

Comments
 (0)