From 925a4f4a6a225b659ebe58cbdbf321dcca89efdf Mon Sep 17 00:00:00 2001 From: MichalKinas Date: Fri, 7 Jul 2023 18:41:14 +0200 Subject: [PATCH] ACS-5506 Add properties to authority service --- .../alfresco/rest/api/impl/GroupsImpl.java | 34 +++++----- .../repo/security/authority/AuthorityDAO.java | 63 +++++++++++-------- .../security/authority/AuthorityDAOImpl.java | 29 +++++++-- .../authority/AuthorityServiceImpl.java | 24 ++++++- .../cmr/security/AuthorityService.java | 42 +++++++++++++ .../authority/AuthorityServiceTest.java | 60 +++++++++++++++++- 6 files changed, 202 insertions(+), 50 deletions(-) diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java index 11939c5521..7c344cb551 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java @@ -27,6 +27,7 @@ package org.alfresco.rest.api.impl; import static org.alfresco.repo.security.authentication.AuthenticationUtil.runAsSystem; +import java.io.Serializable; import java.text.Collator; import java.util.AbstractList; import java.util.ArrayList; @@ -40,6 +41,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.alfresco.model.ContentModel; import org.alfresco.query.CannedQueryPageDetails; import org.alfresco.query.EmptyPagingResults; import org.alfresco.query.PagingRequest; @@ -74,7 +76,6 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.AlfrescoCollator; import org.alfresco.util.Pair; @@ -94,7 +95,6 @@ public class GroupsImpl implements Groups private static final String ZONE = "zone"; private static final String AUTHORITY_NAME = "authorityName"; private static final String ERR_MSG_MODIFY_FIXED_AUTHORITY = "Trying to modify a fixed authority"; - private static final QName PROP_DESCRIPTION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "description"); private final static Map SORT_PARAMS_TO_NAMES; static @@ -158,7 +158,13 @@ public class GroupsImpl implements Groups authorityDisplayName = group.getDisplayName(); } - String authority = authorityService.createAuthority(AuthorityType.GROUP, group.getId(), authorityDisplayName, authorityZones); + HashMap props = new HashMap<>(); + if (StringUtils.isNotEmpty(group.getDescription())) + { + props.put(ContentModel.PROP_DESCRIPTION, group.getDescription()); + } + + String authority = authorityService.createAuthority(AuthorityType.GROUP, group.getId(), authorityDisplayName, authorityZones, props); // Set a given child authority to be included by the given parent // authorities. @@ -167,12 +173,6 @@ public class GroupsImpl implements Groups authorityService.addAuthority(group.getParentIds(), authority); } - if (group.getDescription() != null && !group.getDescription().isEmpty()) - { - NodeRef groupNodeRef = authorityService.getAuthorityNodeRef(authority); - nodeService.setProperty(groupNodeRef, PROP_DESCRIPTION, group.getDescription()); - } - return getGroup(authority, parameters); } @@ -190,10 +190,11 @@ public class GroupsImpl implements Groups handleAuthorityException(ae); } - if (group.getDescription() != null && !group.getDescription().isEmpty()) + if (StringUtils.isNotEmpty(group.getDescription())) { - NodeRef groupNodeRef = authorityService.getAuthorityNodeRef(authorityService.getName(AuthorityType.GROUP, groupId)); - nodeService.setProperty(groupNodeRef, PROP_DESCRIPTION, group.getDescription()); + HashMap props = new HashMap<>(); + props.put(ContentModel.PROP_DESCRIPTION, group.getDescription()); + authorityDAO.setAuthorityProperties(authorityService.getName(AuthorityType.GROUP, groupId), props); } return getGroup(groupId, parameters); @@ -615,9 +616,9 @@ public class GroupsImpl implements Groups group.setHasSubgroups(!authorityService.getContainedAuthorities(AuthorityType.GROUP, authorityInfo.getAuthorityName(), true).isEmpty()); NodeRef groupNodeRef = authorityService.getAuthorityNodeRef(authorityInfo.getAuthorityName()); - String description = nodeService.getProperty(groupNodeRef, PROP_DESCRIPTION) != null ? - nodeService.getProperty(groupNodeRef, PROP_DESCRIPTION).toString() : - ""; + String description = nodeService.getProperty(groupNodeRef, ContentModel.PROP_DESCRIPTION) != null ? + nodeService.getProperty(groupNodeRef, ContentModel.PROP_DESCRIPTION).toString() : + null; group.setDescription(description); // Optionally include @@ -886,8 +887,7 @@ public class GroupsImpl implements Groups validateGroupMemberId(groupMemberId); // Verify if groupMemberId is member of groupId - AuthorityType authorityType = AuthorityType.getAuthorityType(groupMemberId); - Set parents = authorityService.getContainingAuthorities(authorityType, groupMemberId, true); + Set parents = authorityService.getContainingAuthorities(AuthorityType.GROUP, groupMemberId, true); if (!parents.contains(groupId)) { throw new NotFoundException(groupMemberId + " is not member of " + groupId); diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java index 6404f6c255..a6b685d6c5 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java +++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java @@ -1,31 +1,33 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.security.authority; +import java.io.Serializable; import java.util.Collection; +import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; @@ -34,6 +36,7 @@ import org.alfresco.query.PagingResults; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.AuthorityService.AuthorityFilter; +import org.alfresco.service.namespace.QName; public interface AuthorityDAO { @@ -61,6 +64,11 @@ public interface AuthorityDAO */ void createAuthority(String name, String authorityDisplayName, Set authorityZones); + /** + * Create an authority with properties. + */ + void createAuthority(String name, String authorityDisplayName, Set authorityZones, Map properties); + /** * Delete an authority. */ @@ -142,6 +150,11 @@ public interface AuthorityDAO * Set the display name for an authority */ void setAuthorityDisplayName(String authorityName, String authorityDisplayName); + + /** + * Set the properties for an authority + */ + void setAuthorityProperties(String authorityName, Map properties); /** * Get root authorities diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java index f72f4b5177..7625965836 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java +++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java @@ -92,6 +92,7 @@ import org.alfresco.util.PropertyCheck; import org.alfresco.util.SearchLanguageConversion; import org.alfresco.util.registry.NamedObjectRegistry; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; @@ -378,27 +379,35 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor } } - public void createAuthority(String name, String authorityDisplayName, Set authorityZones) + public void createAuthority(String name, String authorityDisplayName, Set authorityZones) { + createAuthority(name, authorityDisplayName, authorityZones, null); + } + + public void createAuthority(String name, String authorityDisplayName, Set authorityZones, Map properties) { - HashMap props = new HashMap(); + HashMap props = new HashMap<>(); /* MNT-11749 : Alfresco allows to create authorities with different char cases, but disallow duplicates */ props.put(ContentModel.PROP_NAME, DigestUtils.md5Hex(name)); props.put(ContentModel.PROP_AUTHORITY_NAME, name); props.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName); + if (MapUtils.isNotEmpty(properties)) + { + props.putAll(properties); + } NodeRef childRef; NodeRef authorityContainerRef = getAuthorityContainer(); childRef = nodeService.createNode(authorityContainerRef, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, namespacePrefixResolver), ContentModel.TYPE_AUTHORITY_CONTAINER, props).getChildRef(); if (authorityZones != null) { - Set zoneRefs = new HashSet(authorityZones.size() * 2); + Set zoneRefs = new HashSet<>(authorityZones.size() * 2); String currentUserDomain = tenantService.getCurrentUserDomain(); for (String authorityZone : authorityZones) { zoneRefs.add(getOrCreateZone(authorityZone)); - zoneAuthorityCache.remove(new Pair(currentUserDomain, authorityZone)); + zoneAuthorityCache.remove(new Pair<>(currentUserDomain, authorityZone)); } - zoneAuthorityCache.remove(new Pair(currentUserDomain, null)); + zoneAuthorityCache.remove(new Pair<>(currentUserDomain, null)); nodeService.addChild(zoneRefs, childRef, ContentModel.ASSOC_IN_ZONE, QName.createQName("cm", name, namespacePrefixResolver)); } authorityLookupCache.put(cacheKey(name), childRef); @@ -1434,6 +1443,16 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor } + public void setAuthorityProperties(String authorityName, Map properties) + { + NodeRef ref = getAuthorityOrNull(authorityName); + if (ref == null) + { + return; + } + properties.forEach((key, value) -> nodeService.setProperty(ref, key, value)); + } + public NodeRef getOrCreateZone(String zoneName) { return getOrCreateZone(zoneName, true); diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java index 0d4ecf8e2a..08a9a8d83c 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java @@ -25,6 +25,7 @@ */ package org.alfresco.repo.security.authority; +import java.io.Serializable; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; @@ -32,6 +33,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -53,6 +55,7 @@ import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; import org.springframework.beans.factory.InitializingBean; import org.springframework.extensions.surf.util.ParameterCheck; @@ -543,6 +546,14 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean { return createAuthority(type, shortName, shortName, getDefaultZones()); } + + /** + * {@inheritDoc} + */ + public String createAuthority(AuthorityType type, String shortName, Map properties) + { + return createAuthority(type, shortName, shortName, getDefaultZones(), properties); + } /** * {@inheritDoc} @@ -643,12 +654,21 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean */ public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones) + { + return createAuthority(type, shortName, authorityDisplayName, authorityZones, null); + } + + /** + * {@inheritDoc} + */ + public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, + Set authorityZones, Map properties) { checkTypeIsMutable(type); String name = getName(type, shortName); - authorityDAO.createAuthority(name, authorityDisplayName, authorityZones); - + authorityDAO.createAuthority(name, authorityDisplayName, authorityZones, properties); + return name; } diff --git a/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java b/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java index 5094302539..25b5c2a294 100644 --- a/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java +++ b/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java @@ -25,7 +25,9 @@ */ package org.alfresco.service.cmr.security; +import java.io.Serializable; import java.util.Collection; +import java.util.Map; import java.util.Set; import org.alfresco.api.AlfrescoPublicApi; @@ -35,6 +37,7 @@ import org.alfresco.repo.security.authority.AuthorityInfo; import org.alfresco.service.Auditable; import org.alfresco.service.NotAuditable; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; /** * The service that encapsulates authorities granted to users. @@ -225,6 +228,24 @@ public interface AuthorityService @Auditable(parameters = {"type", "shortName"}) public String createAuthority(AuthorityType type, String shortName); + /** + * Create an authority with properties. + * + * @param type - + * the type of the authority + * @param shortName - + * the short name of the authority to create + * this will also be set as the default display name for the authority + * + * @param properties - + * properties that will be added to authority + * + * @return the name of the authority (this will be the prefix, if any + * associated with the type appended with the short name) + */ + @Auditable(parameters = {"type", "shortName"}) + public String createAuthority(AuthorityType type, String shortName, Map properties); + /** * Create an authority with a display name and zone. * @@ -242,6 +263,27 @@ public interface AuthorityService @Auditable(parameters = {"type", "shortName", "authorityDisplayName", "authorityZones"}) public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones); + /** + * Create an authority with a display name and zone. + * + * @param type + * the type of the authority + * @param shortName + * the short name of the authority to create + * @param authorityDisplayName + * the display name for the authority + * @param authorityZones + * identifier for external user registry owning the authority or null if not applicable + * + * @param properties - + * properties that will be added to authority + * + * @return the full name of the authority (this will be the prefix, if any associated with the type appended with + * the short name) + */ + @Auditable(parameters = {"type", "shortName", "authorityDisplayName", "authorityZones"}) + public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones, Map properties); + /** * Set an authority to include another authority. For example, adding a * group to a group or adding a user to a group. diff --git a/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java b/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java index 8447461b9b..5299932802 100644 --- a/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java +++ b/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java @@ -581,6 +581,65 @@ public class AuthorityServiceTest extends TestCase // Ignore since we where expecting this } } + + public void testCreateGroupAuthWithProperties() + { + String auth; + String groupName = "TESTGROUP"; + String prefixedGroupName = "GROUP_TESTGROUP"; + String description = "testDesc"; + String title = "testTitle"; + HashMap props = new HashMap<>(); + props.put(ContentModel.PROP_DESCRIPTION, description); + props.put(ContentModel.PROP_TITLE, title); + + // create authority with properties and default zones + auth = pubAuthorityService.createAuthority(AuthorityType.GROUP, groupName, props); + assertTrue(pubAuthorityService.authorityExists(prefixedGroupName)); + NodeRef nodeRef = pubAuthorityService.getAuthorityNodeRef(auth); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION), description); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE), title); + pubAuthorityService.deleteAuthority(auth); + + // create authority with zones and properties + Set zones = new HashSet<>(); + zones.add("Test1"); + zones.add("Test2"); + auth = pubAuthorityService.createAuthority(AuthorityType.GROUP, groupName, prefixedGroupName, zones, props); + assertTrue(pubAuthorityService.authorityExists(prefixedGroupName)); + nodeRef = pubAuthorityService.getAuthorityNodeRef(auth); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION), description); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE), title); + assertEquals(2, pubAuthorityService.getAuthorityZones(auth).size()); + pubAuthorityService.deleteAuthority(auth); + } + + public void testUpdateAuthorityProperties() + { + String auth; + String groupName = "TESTGROUP"; + String prefixedGroupName = "GROUP_TESTGROUP"; + String description = "testDesc"; + String title = "testTitle"; + HashMap props = new HashMap<>(); + props.put(ContentModel.PROP_DESCRIPTION, description); + props.put(ContentModel.PROP_TITLE, title); + + // create authority with properties + auth = pubAuthorityService.createAuthority(AuthorityType.GROUP, groupName, props); + assertTrue(pubAuthorityService.authorityExists(prefixedGroupName)); + + // update authority properties + String newDescription = "newTestDesc"; + String newTitle = "newTestTitle"; + props.put(ContentModel.PROP_DESCRIPTION, newDescription); + props.put(ContentModel.PROP_TITLE, newTitle); + authorityDAO.setAuthorityProperties(auth, props); + NodeRef nodeRef = pubAuthorityService.getAuthorityNodeRef(auth); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION), newDescription); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE), newTitle); + pubAuthorityService.deleteAuthority(auth); + } public void testCreateOwnerAuth() { @@ -1373,7 +1432,6 @@ public class AuthorityServiceTest extends TestCase properties.put(ContentModel.PROP_ORGID, orgId); return properties; } - public void testAuthorityDisplayNames() { String authOne = pubAuthorityService.createAuthority(AuthorityType.GROUP, "One");