REPO-5659: Added ALFRESCO_SYSTEM_ADMINISTRATORS group authority. (#668)

This commit is contained in:
Jamal Kaabi-Mofrad
2021-08-17 12:43:33 +01:00
committed by GitHub
parent 68f34c284a
commit b68e805a37
7 changed files with 227 additions and 127 deletions

View File

@@ -1,61 +1,61 @@
/*
* #%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 <http://www.gnu.org/licenses/>.
* #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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.authority;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.alfresco.model.ContentModel;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnAuthorityAddedToGroup;
import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnAuthorityRemovedFromGroup;
import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnGroupDeleted;
import org.alfresco.repo.security.permissions.PermissionServiceSPI;
import org.alfresco.repo.security.person.UserNameMatcher;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthenticationService;
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.util.Pair;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.surf.util.ParameterCheck;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.alfresco.model.ContentModel;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnAuthorityAddedToGroup;
import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnAuthorityRemovedFromGroup;
import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnGroupDeleted;
import org.alfresco.repo.security.permissions.PermissionServiceSPI;
import org.alfresco.repo.security.person.UserNameMatcher;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthenticationService;
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.util.Pair;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* The default implementation of the authority service.
@@ -64,6 +64,8 @@ import org.springframework.extensions.surf.util.ParameterCheck;
*/
public class AuthorityServiceImpl implements AuthorityService, InitializingBean
{
public static final String GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS_AUTHORITY = PermissionService.GROUP_PREFIX + "ALFRESCO_SYSTEM_ADMINISTRATORS";
private static Set<String> DEFAULT_ZONES = new HashSet<String>();
static
@@ -83,11 +85,11 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
private Set<String> guestSet = Collections.singleton(PermissionService.GUEST_AUTHORITY);
private Set<String> allSet = Collections.singleton(PermissionService.ALL_AUTHORITIES);
private Set<String> adminGroups = Collections.emptySet();
private Set<String> guestGroups = Collections.emptySet();
private ClassPolicyDelegate<OnAuthorityAddedToGroup> onAuthorityAddedToGroups;
private ClassPolicyDelegate<OnAuthorityRemovedFromGroup> onAuthorityRemovedFromGroup;
private ClassPolicyDelegate<OnGroupDeleted> onGroupDeletedDelegate;
private Set<String> guestGroups = Collections.emptySet();
private ClassPolicyDelegate<OnAuthorityAddedToGroup> onAuthorityAddedToGroups;
private ClassPolicyDelegate<OnAuthorityRemovedFromGroup> onAuthorityRemovedFromGroup;
private ClassPolicyDelegate<OnGroupDeleted> onGroupDeletedDelegate;
private PolicyComponent policyComponent;
public AuthorityServiceImpl()
@@ -133,18 +135,18 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
public void setGuestGroups(Set<String> guestGroups)
{
this.guestGroups = guestGroups;
}
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
public void init()
{
onAuthorityAddedToGroups = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnAuthorityAddedToGroup.class);
onAuthorityRemovedFromGroup = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnAuthorityRemovedFromGroup.class);
onGroupDeletedDelegate = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnGroupDeleted.class);
}
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
public void init()
{
onAuthorityAddedToGroups = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnAuthorityAddedToGroup.class);
onAuthorityRemovedFromGroup = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnAuthorityRemovedFromGroup.class);
onGroupDeletedDelegate = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnGroupDeleted.class);
}
@Override
@@ -482,12 +484,12 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
*/
public void addAuthority(Collection<String> parentNames, String childName)
{
authorityDAO.addAuthority(parentNames, childName);
OnAuthorityAddedToGroup policy = onAuthorityAddedToGroups.get(ContentModel.TYPE_AUTHORITY);
for (String parentGroup : parentNames)
{
policy.onAuthorityAddedToGroup(parentGroup, childName);
authorityDAO.addAuthority(parentNames, childName);
OnAuthorityAddedToGroup policy = onAuthorityAddedToGroups.get(ContentModel.TYPE_AUTHORITY);
for (String parentGroup : parentNames)
{
policy.onAuthorityAddedToGroup(parentGroup, childName);
}
}
@@ -565,18 +567,18 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
}
}
authorityDAO.deleteAuthority(name);
permissionServiceSPI.deletePermissions(name);
if (isGroup(type))
{
OnGroupDeleted onGroupDelete = onGroupDeletedDelegate.get(ContentModel.TYPE_AUTHORITY);
onGroupDelete.onGroupDeleted(name, cascade);
permissionServiceSPI.deletePermissions(name);
if (isGroup(type))
{
OnGroupDeleted onGroupDelete = onGroupDeletedDelegate.get(ContentModel.TYPE_AUTHORITY);
onGroupDelete.onGroupDeleted(name, cascade);
}
}
private boolean isGroup(AuthorityType authorityType)
{
return AuthorityType.GROUP == authorityType || AuthorityType.EVERYONE == authorityType;
}
private boolean isGroup(AuthorityType authorityType)
{
return AuthorityType.GROUP == authorityType || AuthorityType.EVERYONE == authorityType;
}
/**
@@ -622,9 +624,9 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
@Override
public void removeAuthority(String parentName, String childName)
{
authorityDAO.removeAuthority(parentName, childName);
OnAuthorityRemovedFromGroup policy = onAuthorityRemovedFromGroup.get(ContentModel.TYPE_AUTHORITY);
authorityDAO.removeAuthority(parentName, childName);
OnAuthorityRemovedFromGroup policy = onAuthorityRemovedFromGroup.get(ContentModel.TYPE_AUTHORITY);
policy.onAuthorityRemovedFromGroup(parentName, childName);
}
@@ -770,6 +772,16 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
return authorityDAO.getShortName(name);
}
@Override
public boolean hasSysAdminAuthority()
{
final String currentUserName = AuthenticationUtil.getRunAsUser();
if (currentUserName == null)
{
return false;
}
return getAuthoritiesForUser(currentUserName).contains(GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS_AUTHORITY);
}
/**
* Lazy load set of authorities. Try not to iterate or ask for the size. Needed for the case where there

View File

@@ -1,28 +1,28 @@
/*
* #%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 <http://www.gnu.org/licenses/>.
* #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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.service.cmr.security;
import java.util.Collection;
@@ -511,4 +511,19 @@ public interface AuthorityService
*/
@Auditable(parameters = {"type"})
public Set<String> findAuthorities(AuthorityType type, String parentAuthority, boolean immediate, String displayNamePattern, String zoneName);
}
/**
* Check the current user has system administration authority.
*
* @return true if the currently authenticated user has the system administration authority, otherwise false
* @throws UnsupportedOperationException if the implementing class (i.e. external clients) doesn't provide an implementation for the {@code hasSysAdminAuthority} operation
*
* @since 7.1
*/
@Auditable
// See PRODMAN-493 -> REPO-5659
default boolean hasSysAdminAuthority()
{
throw new UnsupportedOperationException("hasSysAdminAuthority");
}
}

View File

@@ -63,6 +63,17 @@
<cm:authorityName>GROUP_ALFRESCO_MODEL_ADMINISTRATORS</cm:authorityName>
</view:properties>
</cm:authorityContainer>
<!-- See PRODMAN-493 -> REPO-5659 -->
<cm:authorityContainer view:childName="cm:GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS">
<view:aspects>
<sys:referenceable/>
</view:aspects>
<view:properties>
<sys:node-uuid>GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS</sys:node-uuid>
<cm:name>GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS</cm:name>
<cm:authorityName>GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS</cm:authorityName>
</view:properties>
</cm:authorityContainer>
</sys:children>
</view:associations>
</sys:container>
@@ -110,6 +121,11 @@
view:pathref="${system.authorities_container.childname}/cm:GROUP_ALFRESCO_MODEL_ADMINISTRATORS"
view:childName="cm:GROUP_ALFRESCO_MODEL_ADMINISTRATORS" />
</cm:inZone>
<cm:inZone>
<view:reference
view:pathref="${system.authorities_container.childname}/cm:GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS"
view:childName="cm:GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS" />
</cm:inZone>
</view:associations>
</cm:zone>
<cm:zone view:childName="cm:APP.DEFAULT">
@@ -146,10 +162,15 @@
view:pathref="${system.authorities_container.childname}/cm:GROUP_ALFRESCO_MODEL_ADMINISTRATORS"
view:childName="cm:GROUP_ALFRESCO_MODEL_ADMINISTRATORS" />
</cm:inZone>
<cm:inZone>
<view:reference
view:pathref="${system.authorities_container.childname}/cm:GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS"
view:childName="cm:GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS" />
</cm:inZone>
</view:associations>
</cm:zone>
</sys:children>
</view:associations>
</sys:container>
</view:view>
</view:view>

View File

@@ -40,6 +40,15 @@
view:childName="cm:${alfresco_user_store.adminusername}" />
</cm:member>
</view:associations>
</view:reference>
<!-- See PRODMAN-493 -> REPO-5659 -->
<view:reference view:pathref="${system.authorities_container.childname}/cm:GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS">
<view:associations>
<cm:member>
<view:reference view:pathref="${system.people_container.childname}/cm:${alfresco_user_store.adminusername}"
view:childName="cm:${alfresco_user_store.adminusername}"/>
</cm:member>
</view:associations>
</view:reference>
<view:reference view:pathref="${system.zones_container.childname}/cm:AUTH.ALF">
<view:associations>
@@ -66,4 +75,4 @@
</view:associations>
</view:reference>
</view:view>
</view:view>

View File

@@ -792,6 +792,7 @@
<value>
org.alfresco.service.cmr.security.AuthorityService.hasAdminAuthority=ACL_ALLOW
org.alfresco.service.cmr.security.AuthorityService.hasGuestAuthority=ACL_ALLOW
org.alfresco.service.cmr.security.AuthorityService.hasSysAdminAuthority=ACL_ALLOW
org.alfresco.service.cmr.security.AuthorityService.isAdminAuthority=ACL_ALLOW
org.alfresco.service.cmr.security.AuthorityService.isGuestAuthority=ACL_ALLOW
org.alfresco.service.cmr.security.AuthorityService.countUsers=ACL_ALLOW

View File

@@ -25,6 +25,7 @@
*/
package org.alfresco.repo.security.authority;
import static org.alfresco.repo.security.authority.AuthorityServiceImpl.GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS_AUTHORITY;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -117,9 +118,10 @@ public class AuthorityServiceTest extends TestCase
private static final int DEFAULT_SITE_GRP_CNT = 5; // default number of groups per site
private static final int DEFAULT_SITE_ROOT_GRP_CNT = 1; // default number of root groups per site
private static final int DEFAULT_GRP_CNT = 5; // default (non-site) bootstrap groups -
private static final int DEFAULT_GRP_CNT = 6; // default (non-site) bootstrap groups -
// eg. GROUP_ALFRESCO_ADMINISTRATORS, GROUP_EMAIL_CONTRIBUTORS, GROUP_SITE_ADMINISTRATORS,
// GROUP_ALFRESCO_SEARCH_ADMINISTRATORS, GROUP_ALFRESCO_MODEL_ADMINISTRATORS
// GROUP_ALFRESCO_SEARCH_ADMINISTRATORS, GROUP_ALFRESCO_MODEL_ADMINISTRATORS,
// GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS
private int SITE_CNT = 0;
private int GRP_CNT = 0;
@@ -467,8 +469,8 @@ public class AuthorityServiceTest extends TestCase
assertTrue(authorityService.hasAdminAuthority());
assertTrue(pubAuthorityService.hasAdminAuthority());
Set<String> authorities = authorityService.getAuthorities();
// 6 => [GROUP_ALFRESCO_ADMINISTRATORS, GROUP_EMAIL_CONTRIBUTORS, GROUP_EVERYONE, GROUP_SITE_ADMINISTRATORS, ROLE_ADMINISTRATOR, GROUP_ALFRESCO_SEARCH_ADMINISTRATORS, GROUP_ALFRESCO_MODEL_ADMINISTRATORS]
assertEquals("Unexpected result: " + authorities, 7 + (SITE_CNT*2), authorityService.getAuthorities().size());
// 8 => [GROUP_ALFRESCO_ADMINISTRATORS, GROUP_EMAIL_CONTRIBUTORS, GROUP_EVERYONE, GROUP_SITE_ADMINISTRATORS, ROLE_ADMINISTRATOR, GROUP_ALFRESCO_SEARCH_ADMINISTRATORS, GROUP_ALFRESCO_MODEL_ADMINISTRATORS, GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS]
assertEquals("Unexpected result: " + authorities, 8 + (SITE_CNT*2), authorityService.getAuthorities().size());
}
public void testNoUser()
@@ -1773,6 +1775,46 @@ public class AuthorityServiceTest extends TestCase
personService.deletePerson(username);
}
public void testAdminHasSysAdminAuthority()
{
authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
assertTrue(authorityService.hasAdminAuthority());
assertTrue("By default, Admin should be member of Alfresco_System_Administrators group.",
pubAuthorityService.hasSysAdminAuthority());
}
public void testSysAdminGroup()
{
personService.getPerson("andy");
// Make sure Andy is not part of ALFRESCO_ADMINISTRATORS group
String adminGroup = authorityService.getName(AuthorityType.GROUP, "ALFRESCO_ADMINISTRATORS");
authorityService.removeAuthority(adminGroup, "andy");
assertFalse(authorityService.isAdminAuthority("andy"));
// Set the current authentication to Andy, so we can check the runAsUser
authenticationComponent.setCurrentUser("andy");
assertFalse("Andy hasn't been added to the Alfresco_System_Administrators group yet.",
pubAuthorityService.hasSysAdminAuthority());
// Set the current authentication to admin in order to add Andy to the group
authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
pubAuthorityService.addAuthority(GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS_AUTHORITY, "andy");
// Set the current authentication to Andy, so we can check the runAsUser
authenticationComponent.setCurrentUser("andy");
assertTrue("Andy is a member of the Alfresco_System_Administrators group",
pubAuthorityService.hasSysAdminAuthority());
// Set the current authentication to admin in order to remove Andy from the group
authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
pubAuthorityService.removeAuthority(GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS_AUTHORITY, "andy");
// Set the current authentication to Andy, so we can check the runAsUser
authenticationComponent.setCurrentUser("andy");
assertFalse("Andy has been removed from the Alfresco_System_Administrators group.",
pubAuthorityService.hasSysAdminAuthority());
}
private <T extends Policy> T createClassPolicy(Class<T> policyInterface, QName policyQName, QName triggerOnClass)
{
T policy = mock(policyInterface);