mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-29 15:21:53 +00:00
Compare commits
80 Commits
25.2.0.17
...
feature/MN
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84b38af65b | ||
|
|
f1862c9636 | ||
|
|
231075fd5e | ||
|
|
979420879c | ||
|
|
db330e28f5 | ||
|
|
bae0573636 | ||
|
|
8089fc2572 | ||
|
|
1c4fe53c0f | ||
|
|
7a8aa1a2c1 | ||
|
|
e08ba1fd4f | ||
|
|
4f40bd0687 | ||
|
|
a3578f7baa | ||
|
|
8e8b9c868f | ||
|
|
f77b3b79e5 | ||
|
|
3a7157f4a7 | ||
|
|
d6b979f341 | ||
|
|
a090de4e71 | ||
|
|
03621db30a | ||
|
|
766a6def2b | ||
|
|
117804fb68 | ||
|
|
f03e6761ce | ||
|
|
74c8288206 | ||
|
|
c0bd0a680b | ||
|
|
8645cdc76d | ||
|
|
5055eec2df | ||
|
|
892f41d6fd | ||
|
|
075b02baee | ||
|
|
7c8a75ce6c | ||
|
|
cb0a925e27 | ||
|
|
c7d2699f7e | ||
|
|
b942b55193 | ||
|
|
c1100fe983 | ||
|
|
62236c90f5 | ||
|
|
eabdab91fb | ||
|
|
4f83076cfe | ||
|
|
7eda1d420f | ||
|
|
411388d62d | ||
|
|
245d1317ac | ||
|
|
ee5e34ca32 | ||
|
|
c4dcef73e1 | ||
|
|
4f53fee1fc | ||
|
|
d163410e3d | ||
|
|
9ca251edba | ||
|
|
193cb9b30d | ||
|
|
e9a36f67fe | ||
|
|
c18a58caea | ||
|
|
11659ab917 | ||
|
|
89b1049809 | ||
|
|
192c105719 | ||
|
|
b8fc8efa07 | ||
|
|
2e851cf88d | ||
|
|
ebf081c731 | ||
|
|
b979701264 | ||
|
|
aa0d02abf2 | ||
|
|
2f7b8d50a3 | ||
|
|
800736a025 | ||
|
|
b8b7e5193e | ||
|
|
808faa71b3 | ||
|
|
0bd476968b | ||
|
|
e51e5e8ca5 | ||
|
|
46db14d5ff | ||
|
|
b5fa73ca3b | ||
|
|
c962daae3b | ||
|
|
8efc559b09 | ||
|
|
08628732fc | ||
|
|
7f74bf7b3e | ||
|
|
390073b153 | ||
|
|
68c87f69c5 | ||
|
|
2b936050c8 | ||
|
|
28184ca69a | ||
|
|
e05c74813e | ||
|
|
e05a1d9ba9 | ||
|
|
5aab15a77a | ||
|
|
5d267c8d60 | ||
|
|
18fc9a58b4 | ||
|
|
6a7ba876b7 | ||
|
|
65bdb242ec | ||
|
|
5a537b301a | ||
|
|
515b894241 | ||
|
|
4978d9e790 |
@@ -1273,7 +1273,7 @@
|
||||
"filename": "repository/src/main/resources/alfresco/repository.properties",
|
||||
"hashed_secret": "84551ae5442affc9f1a2d3b4c86ae8b24860149d",
|
||||
"is_verified": false,
|
||||
"line_number": 770,
|
||||
"line_number": 771,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@@ -1868,5 +1868,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2025-03-27T23:45:41Z"
|
||||
"generated_at": "2025-04-22T06:32:47Z"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rest.rm.community.model;
|
||||
|
||||
public record CapabilityModel(String name, String title, String description, GroupModel group, int index)
|
||||
{}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rest.rm.community.model;
|
||||
|
||||
public record GroupModel(String id, String title)
|
||||
{}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*-
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rest.rm.community.model.role;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import org.alfresco.rest.rm.community.model.CapabilityModel;
|
||||
import org.alfresco.utility.model.TestModel;
|
||||
|
||||
/**
|
||||
* POJO for role
|
||||
*/
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Role extends TestModel
|
||||
{
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private String name;
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private List<CapabilityModel> capabilities;
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private String displayLabel;
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private String groupShortName;
|
||||
|
||||
private List<String> assignedUsers;
|
||||
|
||||
private List<String> assignedGroups;
|
||||
|
||||
private String roleGroupName;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Role role = (Role) o;
|
||||
return Objects.equals(name, role.name) && Objects.equals(capabilities, role.capabilities)
|
||||
&& Objects.equals(displayLabel, role.displayLabel) && Objects.equals(groupShortName, role.groupShortName) && Objects.equals(assignedUsers, role.assignedUsers)
|
||||
&& Objects.equals(assignedGroups, role.assignedGroups) && Objects.equals(roleGroupName, role.roleGroupName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(name, capabilities, displayLabel, groupShortName, assignedUsers, assignedGroups, roleGroupName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*-
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rest.rm.community.model.role;
|
||||
|
||||
import org.alfresco.rest.core.RestModels;
|
||||
|
||||
public class RoleCollection extends RestModels<RoleEntry, RoleCollection>
|
||||
{}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*-
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rest.rm.community.model.role;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import org.alfresco.rest.core.RestModels;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RoleEntry extends RestModels<Role, RoleEntry>
|
||||
{
|
||||
@JsonProperty
|
||||
private Role entry;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ package org.alfresco.rest.rm.community.model.user;
|
||||
*/
|
||||
public enum UserRoles
|
||||
{
|
||||
IN_PLACE_WRITERS("ExtendedWriters", "In-Place Writers"), ROLE_RM_ADMIN("Administrator", "Records Management Administrator"), ROLE_RM_MANAGER("RecordsManager", "Records Management Manager"), ROLE_RM_POWER_USER("PowerUser", "Records Management Power User"), ROLE_RM_SECURITY_OFFICER("SecurityOfficer", "Records Management Security Officer"), ROLE_RM_USER("User", "Records Management User");
|
||||
IN_PLACE_WRITERS("ExtendedWriters", "In-Place Writers"), ROLE_RM_ADMIN("Administrator", "Records Management Administrator"), ROLE_RM_MANAGER("RecordsManager", "Records Management Manager"), ROLE_RM_POWER_USER("PowerUser", "Records Management Power User"), ROLE_RM_SECURITY_OFFICER("SecurityOfficer", "Records Management Security Officer"), ROLE_RM_USER("User", "Records Management User"), IN_PLACE_READERS("ExtendedReaders", "In-Place Readers");
|
||||
|
||||
public final String roleId;
|
||||
public final String displayName;
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.alfresco.rest.rm.community.model.hold.Hold;
|
||||
import org.alfresco.rest.rm.community.model.hold.HoldCollection;
|
||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
|
||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryCollection;
|
||||
import org.alfresco.rest.rm.community.model.role.RoleCollection;
|
||||
import org.alfresco.rest.rm.community.requests.RMModelRequest;
|
||||
|
||||
/**
|
||||
@@ -303,4 +304,39 @@ public class FilePlanAPI extends RMModelRequest
|
||||
{
|
||||
return getHolds(filePlanId, EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the roles of a file plan.
|
||||
*
|
||||
* @param filePlanId
|
||||
* The identifier of a file plan
|
||||
* @param parameters
|
||||
* The URL parameters to add
|
||||
* @return The {Pagination and RoleModel Entries} for the given {@code filePlanId}
|
||||
* @throws RuntimeException
|
||||
* for the following cases:
|
||||
* <ul>
|
||||
* <li>authentication fails</li>
|
||||
* <li>current user does not have permission to read {@code filePlanId}</li>
|
||||
* <li>{@code filePlanId} does not exist</li>
|
||||
* </ul>
|
||||
*/
|
||||
public RoleCollection getFilePlanRoles(String filePlanId, String parameters)
|
||||
{
|
||||
mandatoryString("filePlanId", filePlanId);
|
||||
return getRmRestWrapper().processModels(RoleCollection.class, simpleRequest(
|
||||
GET,
|
||||
"file-plans/{filePlanId}/roles?{parameters}",
|
||||
filePlanId,
|
||||
parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #getFilePlanRoles(String, String)}
|
||||
*/
|
||||
public RoleCollection getFilePlanRoles(String filePlanId)
|
||||
{
|
||||
return getFilePlanRoles(filePlanId, EMPTY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.SearchNodeModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
|
||||
import org.alfresco.rest.v0.SearchAPI;
|
||||
import org.alfresco.utility.Utility;
|
||||
import org.alfresco.utility.data.DataUserAIS;
|
||||
@@ -127,6 +128,10 @@ public class BaseRMRestTest extends RestTest
|
||||
@Getter(value = PROTECTED)
|
||||
private SearchAPI searchApi;
|
||||
|
||||
@Autowired
|
||||
@Getter(PROTECTED)
|
||||
private RMRolesAndActionsAPI rmRolesAndActionsV0API;
|
||||
|
||||
protected static final String iso8601_DateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ package org.alfresco.rest.rm.community.fileplans;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
import static org.springframework.http.HttpStatus.CONFLICT;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
|
||||
@@ -56,19 +57,27 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
|
||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_CONTAINER_TYPE;
|
||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.IN_PLACE_READERS;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.IN_PLACE_WRITERS;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_ADMIN;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_MANAGER;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_POWER_USER;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_SECURITY_OFFICER;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_USER;
|
||||
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
|
||||
import static org.alfresco.utility.data.RandomData.getRandomName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
|
||||
import org.alfresco.rest.rm.community.base.DataProviderClass;
|
||||
import org.alfresco.rest.rm.community.model.CapabilityModel;
|
||||
import org.alfresco.rest.rm.community.model.fileplan.FilePlan;
|
||||
import org.alfresco.rest.rm.community.model.fileplan.FilePlanProperties;
|
||||
import org.alfresco.rest.rm.community.model.hold.Hold;
|
||||
@@ -76,6 +85,9 @@ import org.alfresco.rest.rm.community.model.hold.HoldCollection;
|
||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
|
||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryCollection;
|
||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryProperties;
|
||||
import org.alfresco.rest.rm.community.model.role.Role;
|
||||
import org.alfresco.rest.rm.community.model.role.RoleCollection;
|
||||
import org.alfresco.rest.rm.community.model.user.UserCapabilities;
|
||||
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
|
||||
import org.alfresco.utility.constants.ContainerName;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
@@ -87,6 +99,7 @@ import org.alfresco.utility.report.Bug;
|
||||
* @author Rodica Sutu
|
||||
* @since 2.6
|
||||
*/
|
||||
@SuppressWarnings("PMD.UnitTestShouldIncludeAssert")
|
||||
public class FilePlanTests extends BaseRMRestTest
|
||||
{
|
||||
// ** Number of children (for children creation test) */
|
||||
@@ -266,7 +279,7 @@ public class FilePlanTests extends BaseRMRestTest
|
||||
* When I ask the API to create a root record category
|
||||
* Then it is created as a root record category
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When I use the API to create a folder (cm:folder type) into the fileplan
|
||||
@@ -314,7 +327,7 @@ public class FilePlanTests extends BaseRMRestTest
|
||||
* When I ask the API to create a root category having the same name
|
||||
* Then the response code received is 409 - name clashes with an existing node
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* Given a root category
|
||||
* When I ask the API to create a root category having the same name with autoRename parameter on true
|
||||
@@ -594,4 +607,171 @@ public class FilePlanTests extends BaseRMRestTest
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When rmAdmin user ask the API for roles
|
||||
* It provides list of all default roles
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void listFilePlanAllDefaultRoles()
|
||||
{
|
||||
List<String> defaultRolesDisplayNames = asList(IN_PLACE_READERS.displayName, ROLE_RM_ADMIN.displayName, ROLE_RM_MANAGER.displayName, ROLE_RM_POWER_USER.displayName, ROLE_RM_USER.displayName, IN_PLACE_WRITERS.displayName, ROLE_RM_SECURITY_OFFICER.displayName);
|
||||
// Call to new API to get the roles and capabilities
|
||||
RoleCollection roleCollection = getRestAPIFactory().getFilePlansAPI().getFilePlanRoles(FILE_PLAN_ALIAS);
|
||||
assertStatusCode(OK);
|
||||
roleCollection.getEntries().forEach(roleModelEntry -> {
|
||||
Role role = roleModelEntry.getEntry();
|
||||
assertTrue(defaultRolesDisplayNames.contains(role.getDisplayLabel()));
|
||||
assertNotNull(role.getCapabilities());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When rmAdmin user ask the API for roles with SystemRoles as false
|
||||
* It provides list of all roles excluding SystemRoles
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void listFilePlanAllRolesExcludeSystemRoles()
|
||||
{
|
||||
String parameters = "where=(systemRoles=false)";
|
||||
List<String> systemRolesDisplayNames = asList(IN_PLACE_WRITERS.displayName, IN_PLACE_READERS.displayName);
|
||||
// Call to new API to get the roles and capabilities
|
||||
RoleCollection roleCollection = getRestAPIFactory().getFilePlansAPI().getFilePlanRoles(FILE_PLAN_ALIAS, parameters);
|
||||
assertStatusCode(OK);
|
||||
roleCollection.getEntries().forEach(roleModelEntry -> {
|
||||
Role role = roleModelEntry.getEntry();
|
||||
assertFalse(systemRolesDisplayNames.contains(role.getDisplayLabel()));
|
||||
assertNotNull(role.getCapabilities());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When a non-RM user asks the API for the roles
|
||||
* Then the status code 403 (Permission denied) is return
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void nonRmUserFilePlanRoles()
|
||||
{
|
||||
// Create a random user
|
||||
UserModel nonRMuser = getDataUser().createRandomTestUser("testUser");
|
||||
// Call to new API to get the roles and capabilities
|
||||
getRestAPIFactory().getFilePlansAPI(nonRMuser).getFilePlanRoles(FILE_PLAN_ALIAS);
|
||||
assertStatusCode(FORBIDDEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When a RM_Manager user asks the API for the roles
|
||||
* returns the RM_Manager role and capabilities
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void rmManagerFilePlanRolesAndCapabilities()
|
||||
{
|
||||
// Create a random user
|
||||
UserModel managerUser = getDataUser().createRandomTestUser("managerUser");
|
||||
// Assign RecordsManager role to user
|
||||
getRestAPIFactory().getRMUserAPI().assignRoleToUser(managerUser.getUsername(), ROLE_RM_MANAGER.roleId);
|
||||
String parameters = "where=(personId='" + managerUser.getUsername() + "')";
|
||||
// Call to new API to get the roles and capabilities
|
||||
RoleCollection roleCollection = getRestAPIFactory().getFilePlansAPI(managerUser).getFilePlanRoles(FILE_PLAN_ALIAS, parameters);
|
||||
roleCollection.getEntries().forEach(roleModelEntry -> {
|
||||
Role role = roleModelEntry.getEntry();
|
||||
assertEquals(ROLE_RM_MANAGER.displayName, role.getDisplayLabel());
|
||||
assertNotNull(role.getCapabilities());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When a User with more than one role asks the API for the roles and relation
|
||||
* returns the roles and capabilities
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void multipleRoleUserFilePlanRolesAndCapabilities()
|
||||
{
|
||||
// Create a random user
|
||||
UserModel rmUser = getDataUser().createRandomTestUser("rmUser");
|
||||
// Assign rmUser role to user
|
||||
getRestAPIFactory().getRMUserAPI().assignRoleToUser(rmUser.getUsername(), ROLE_RM_USER.roleId);
|
||||
getRestAPIFactory().getRMUserAPI().assignRoleToUser(rmUser.getUsername(), ROLE_RM_POWER_USER.roleId);
|
||||
String parameters = "where=(personId='" + rmUser.getUsername() + "')";
|
||||
// Call to new API to get the roles and capabilities
|
||||
RoleCollection roleCollection = getRestAPIFactory().getFilePlansAPI(rmUser).getFilePlanRoles(FILE_PLAN_ALIAS, parameters);
|
||||
assertStatusCode(OK);
|
||||
assertEquals(roleCollection.getEntries().size(), 2);
|
||||
roleCollection.getEntries().forEach(roleModelEntry -> {
|
||||
Role role = roleModelEntry.getEntry();
|
||||
assertTrue(role.getDisplayLabel().equals(ROLE_RM_USER.displayName) || role.getDisplayLabel().equals(ROLE_RM_POWER_USER.displayName));
|
||||
assertNotNull(role.getCapabilities());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When a new user with a new role asks the API for the roles and relation
|
||||
* returns the new role and new capabilities
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void newRoleUserFilePlanRolesAndCapabilities()
|
||||
{
|
||||
/** A list of capabilities. */
|
||||
Set<String> newCapabilities = newHashSet(UserCapabilities.VIEW_RECORDS_CAP, UserCapabilities.DECLARE_RECORDS_CAP);
|
||||
// Create a new role using old API
|
||||
getRmRolesAndActionsV0API().createRole(getAdminUser().getUsername(), getAdminUser().getPassword(), "NewTestRole",
|
||||
"New Role Label", newCapabilities);
|
||||
// Create a random user
|
||||
UserModel rmNewUser = getDataUser().createRandomTestUser("rmPowerUser");
|
||||
// Assign New role to user
|
||||
getRestAPIFactory().getRMUserAPI().assignRoleToUser(rmNewUser.getUsername(), "NewTestRole");
|
||||
String parameters = "where=(personId='" + rmNewUser.getUsername() + "')";
|
||||
// Call to new API to get the roles and capabilities
|
||||
RoleCollection roleCollection = getRestAPIFactory().getFilePlansAPI(rmNewUser).getFilePlanRoles(FILE_PLAN_ALIAS, parameters);
|
||||
assertStatusCode(OK);
|
||||
assertEquals(roleCollection.getEntries().size(), 1);
|
||||
roleCollection.getEntries().forEach(roleModelEntry -> {
|
||||
List<CapabilityModel> capabilities = roleModelEntry.getEntry().getCapabilities();
|
||||
capabilities.forEach(capabilityModel -> {
|
||||
assertTrue(newCapabilities.contains(capabilityModel.name()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Given that a file plan exists
|
||||
* When API call happens with Capability filter
|
||||
* returns roles associated with the capability
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void filePlanRolesAndCapabilitiesFilter()
|
||||
{
|
||||
String parameters = "where=(systemRoles=true and capabilityName in ('ManageRules'))";
|
||||
// Call to new API to get the roles and capabilities, filter by capability, include assigned users
|
||||
RoleCollection roleCollection = getRestAPIFactory().getFilePlansAPI().getFilePlanRoles(FILE_PLAN_ALIAS, parameters);
|
||||
assertStatusCode(OK);
|
||||
assertEquals(roleCollection.getEntries().size(), 1);
|
||||
roleCollection.getEntries().forEach(roleModelEntry -> {
|
||||
Role role = roleModelEntry.getEntry();
|
||||
assertEquals(ROLE_RM_ADMIN.displayName, role.getDisplayLabel());
|
||||
assertNotNull(role.getCapabilities());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -134,6 +134,16 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(null).search(searchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
|
||||
RestRequestQueryModel ancestorReq = getContentFromFolderAndAllSubfoldersQuery(rootFolder.getNodeRefWithoutVersion());
|
||||
SearchRequest ancestorSearchRequest = new SearchRequest();
|
||||
ancestorSearchRequest.setQuery(ancestorReq);
|
||||
|
||||
STEP("Wait until paths are indexed.");
|
||||
// to improve stability on CI - seems that sometimes during big load we need to wait longer for the condition
|
||||
await().atMost(120, TimeUnit.SECONDS)
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(null).search(ancestorSearchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
|
||||
holdBulkOperation = HoldBulkOperation.builder()
|
||||
.query(queryReq)
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -78,6 +78,12 @@
|
||||
<property name="transactionService" ref="transactionService" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.alfresco.rm.rest.api.fileplans.FilePlanRolesRelation">
|
||||
<property name="apiUtils" ref="apiUtils" />
|
||||
<property name="rmRoles" ref="rm.roles" />
|
||||
<property name="filePlanService" ref="FilePlanService" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.alfresco.rm.rest.api.holds.HoldsEntityResource" >
|
||||
<property name="holdService" ref="HoldService" />
|
||||
<property name="apiUtils" ref="apiUtils" />
|
||||
@@ -228,6 +234,11 @@
|
||||
<property name="siteSurfConfig" ref="rm.siteSurfConfig" />
|
||||
</bean>
|
||||
|
||||
<bean id="rm.roles" class="org.alfresco.rm.rest.api.impl.RMRolesImpl">
|
||||
<property name="nodesModelFactory" ref="nodesModelFactory" />
|
||||
<property name="filePlanRoleService" ref="FilePlanRoleService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="rm.siteSurfConfig" class="org.alfresco.rest.api.impl.SiteSurfConfig">
|
||||
<property name="configPath" value="alfresco/module/org_alfresco_module_rm/bootstrap/site"/>
|
||||
</bean>
|
||||
@@ -280,4 +291,4 @@
|
||||
<property name="beanName" value="restJsonModule" />
|
||||
<property name="extendingBeanName" value="rm.restJsonModule" />
|
||||
</bean>
|
||||
</beans>
|
||||
</beans>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api;
|
||||
|
||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||
import org.alfresco.rm.rest.api.model.RoleModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* RM Roles API
|
||||
*/
|
||||
public interface RMRoles
|
||||
{
|
||||
|
||||
String PARAM_INCLUDE_ASSIGNED_USERS = "assignedUsers";
|
||||
String PARAM_INCLUDE_ASSIGNED_GROUPS = "assignedGroups";
|
||||
String PARAM_INCLUDE_SYSTEM_ROLES = "systemRoles";
|
||||
String PARAM_CAPABILITY_NAME = "capabilityName";
|
||||
String PARAM_PERSON_ID = "personId";
|
||||
|
||||
/**
|
||||
* Gets a list of roles.
|
||||
*
|
||||
* @param filePlan
|
||||
* the file plan node reference
|
||||
* @param parameters
|
||||
* the {@link Parameters} object to get the parameters passed into the request including: - filter, sort & paging params (where, orderBy, skipCount, maxItems) - include param (personId, includeSystemRoles)
|
||||
* @return a paged list of {@code org.alfresco.rm.rest.api.model.RoleModel} objects
|
||||
*/
|
||||
CollectionWithPagingInfo<RoleModel> getRoles(NodeRef filePlan, Parameters parameters);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api.fileplans;
|
||||
|
||||
import static org.alfresco.util.ParameterCheck.mandatory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
|
||||
import org.alfresco.rest.framework.resource.RelationshipResource;
|
||||
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
|
||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||
import org.alfresco.rm.rest.api.RMRoles;
|
||||
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
|
||||
import org.alfresco.rm.rest.api.model.RoleModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
@RelationshipResource(name = "roles", entityResource = FilePlanEntityResource.class, title = "Roles in a file plan")
|
||||
public class FilePlanRolesRelation implements RelationshipResourceAction.Read<RoleModel>, InitializingBean
|
||||
{
|
||||
private RMRoles rmRoles;
|
||||
private FilePlanService filePlanService;
|
||||
private FilePlanComponentsApiUtils apiUtils;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
mandatory("rmRoles", this.rmRoles);
|
||||
mandatory("apiUtils", this.apiUtils);
|
||||
mandatory("filePlanService", this.filePlanService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionWithPagingInfo<RoleModel> readAll(String filePlanId, Parameters params)
|
||||
{
|
||||
NodeRef filePlanNodeRef = getFilePlan(filePlanId);
|
||||
if (filePlanNodeRef == null)
|
||||
{
|
||||
throw new EntityNotFoundException(filePlanId);
|
||||
}
|
||||
|
||||
return rmRoles.getRoles(filePlanNodeRef, params);
|
||||
}
|
||||
|
||||
private NodeRef getFilePlan(String filePlanId)
|
||||
{
|
||||
NodeRef filePlanNodeRef = apiUtils.lookupAndValidateNodeType(filePlanId, RecordsManagementModel.TYPE_FILE_PLAN);
|
||||
if (!FilePlanComponentsApiUtils.FILE_PLAN_ALIAS.equals(filePlanId))
|
||||
{
|
||||
filePlanNodeRef = filePlanService.getFilePlan(filePlanNodeRef);
|
||||
}
|
||||
return filePlanNodeRef;
|
||||
}
|
||||
|
||||
public void setRmRoles(RMRoles rmRoles)
|
||||
{
|
||||
this.rmRoles = rmRoles;
|
||||
}
|
||||
|
||||
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
|
||||
{
|
||||
this.apiUtils = apiUtils;
|
||||
}
|
||||
|
||||
public void setFilePlanService(FilePlanService filePlanService)
|
||||
{
|
||||
this.filePlanService = filePlanService;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ package org.alfresco.rm.rest.api.impl;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -42,12 +43,15 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry;
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.Group;
|
||||
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition;
|
||||
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinitionImpl;
|
||||
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
|
||||
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEvent;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.role.Role;
|
||||
import org.alfresco.rest.api.Nodes;
|
||||
import org.alfresco.rest.api.model.AssocChild;
|
||||
import org.alfresco.rest.api.model.ContentInfo;
|
||||
@@ -55,7 +59,9 @@ import org.alfresco.rest.api.model.Node;
|
||||
import org.alfresco.rest.api.model.UserInfo;
|
||||
import org.alfresco.rest.framework.jacksonextensions.BeanPropertiesFilter;
|
||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||
import org.alfresco.rm.rest.api.model.CapabilityModel;
|
||||
import org.alfresco.rm.rest.api.model.FilePlan;
|
||||
import org.alfresco.rm.rest.api.model.GroupModel;
|
||||
import org.alfresco.rm.rest.api.model.HoldModel;
|
||||
import org.alfresco.rm.rest.api.model.RMNode;
|
||||
import org.alfresco.rm.rest.api.model.Record;
|
||||
@@ -66,6 +72,7 @@ import org.alfresco.rm.rest.api.model.RetentionPeriod;
|
||||
import org.alfresco.rm.rest.api.model.RetentionSchedule;
|
||||
import org.alfresco.rm.rest.api.model.RetentionScheduleActionDefinition;
|
||||
import org.alfresco.rm.rest.api.model.RetentionSteps;
|
||||
import org.alfresco.rm.rest.api.model.RoleModel;
|
||||
import org.alfresco.rm.rest.api.model.Transfer;
|
||||
import org.alfresco.rm.rest.api.model.TransferChild;
|
||||
import org.alfresco.rm.rest.api.model.TransferContainer;
|
||||
@@ -696,6 +703,36 @@ public class ApiNodesModelFactory
|
||||
(String) info.getProperties().get(RecordsManagementModel.PROP_HOLD_REASON));
|
||||
}
|
||||
|
||||
public RoleModel createRoleModel(Role role, List<String> assignedUsers, List<String> assignedGroups)
|
||||
{
|
||||
return new RoleModel(role.getName(),
|
||||
role.getDisplayLabel(),
|
||||
role.getCapabilities()
|
||||
.stream()
|
||||
.map(this::createCapabilityModel)
|
||||
.sorted(Comparator.comparing(CapabilityModel::name))
|
||||
.toList(),
|
||||
role.getRoleGroupName(),
|
||||
role.getGroupShortName(),
|
||||
assignedUsers,
|
||||
assignedGroups);
|
||||
}
|
||||
|
||||
public CapabilityModel createCapabilityModel(Capability capability)
|
||||
{
|
||||
return new CapabilityModel(capability.getName(), capability.getTitle(), capability.getDescription(),
|
||||
createGroupModel(capability.getGroup()), capability.getIndex());
|
||||
}
|
||||
|
||||
public GroupModel createGroupModel(Group group)
|
||||
{
|
||||
if (group == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new GroupModel(group.getId(), group.getTitle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object of type FilePlan
|
||||
*
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.role.Role;
|
||||
import org.alfresco.rest.antlr.WhereClauseParser;
|
||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
|
||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||
import org.alfresco.rest.framework.resource.parameters.where.Query;
|
||||
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
|
||||
import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker;
|
||||
import org.alfresco.rm.rest.api.RMRoles;
|
||||
import org.alfresco.rm.rest.api.model.RoleModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
public class RMRolesImpl implements RMRoles
|
||||
{
|
||||
private ApiNodesModelFactory nodesModelFactory;
|
||||
private FilePlanRoleService filePlanRoleService;
|
||||
|
||||
private static final Set<String> LIST_ROLES_QUERY_PROPERTIES = new HashSet<>(List.of(PARAM_PERSON_ID, PARAM_INCLUDE_SYSTEM_ROLES, PARAM_CAPABILITY_NAME));
|
||||
|
||||
@Override
|
||||
public CollectionWithPagingInfo<RoleModel> getRoles(NodeRef filePlan, Parameters parameters)
|
||||
{
|
||||
var rolesFilter = getRolesFilter(parameters.getQuery());
|
||||
var roles = getRolesByFilter(filePlan, rolesFilter);
|
||||
|
||||
var filteredRoles = roles.stream()
|
||||
.map(role -> createRoleModel(filePlan, role, parameters.getInclude()))
|
||||
.filter(hasRoleCapabilities(rolesFilter.getCapabilities()))
|
||||
.toList();
|
||||
var page = filteredRoles
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(RoleModel::name))
|
||||
.skip(parameters.getPaging().getSkipCount())
|
||||
.limit(parameters.getPaging().getMaxItems())
|
||||
.collect(Collectors.toCollection(LinkedList::new));
|
||||
|
||||
int totalItems = filteredRoles.size();
|
||||
boolean hasMore = parameters.getPaging().getSkipCount() + parameters.getPaging().getMaxItems() < totalItems;
|
||||
return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, hasMore, totalItems);
|
||||
}
|
||||
|
||||
private Predicate<RoleModel> hasRoleCapabilities(List<String> capabilities)
|
||||
{
|
||||
return role -> capabilities == null ||
|
||||
capabilities.isEmpty() ||
|
||||
role.capabilities().stream().anyMatch(capability -> capabilities.contains(capability.name()));
|
||||
}
|
||||
|
||||
private Set<Role> getRolesByFilter(NodeRef filePlan, RolesFilter rolesFilter)
|
||||
{
|
||||
if (rolesFilter.getPersonId() != null)
|
||||
{
|
||||
return filePlanRoleService.getRolesByUser(filePlan, rolesFilter.getPersonId(), rolesFilter.includeSystemRoles());
|
||||
}
|
||||
else
|
||||
{
|
||||
return filePlanRoleService.getRoles(filePlan, rolesFilter.includeSystemRoles());
|
||||
}
|
||||
}
|
||||
|
||||
private RoleModel createRoleModel(NodeRef filePlan, Role role, List<String> include)
|
||||
{
|
||||
List<String> assignedUsers = getAssignedUsers(filePlan, role, include);
|
||||
List<String> assignedGroups = getAssignedGroups(filePlan, role, include);
|
||||
|
||||
return nodesModelFactory.createRoleModel(role, assignedUsers, assignedGroups);
|
||||
}
|
||||
|
||||
private List<String> getAssignedUsers(NodeRef filePlan, Role role, List<String> include)
|
||||
{
|
||||
if (include != null && include.contains(PARAM_INCLUDE_ASSIGNED_USERS))
|
||||
{
|
||||
return new ArrayList<>(filePlanRoleService.getAllAssignedToRole(filePlan, role.getName()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getAssignedGroups(NodeRef filePlan, Role role, List<String> include)
|
||||
{
|
||||
if (include != null && include.contains(PARAM_INCLUDE_ASSIGNED_GROUPS))
|
||||
{
|
||||
return new ArrayList<>(filePlanRoleService.getGroupsAssignedToRole(filePlan, role.getName()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory)
|
||||
{
|
||||
this.nodesModelFactory = nodesModelFactory;
|
||||
}
|
||||
|
||||
public void setFilePlanRoleService(FilePlanRoleService filePlanRoleService)
|
||||
{
|
||||
this.filePlanRoleService = filePlanRoleService;
|
||||
}
|
||||
|
||||
private RolesFilter getRolesFilter(Query queryParameters)
|
||||
{
|
||||
var rolesFilterBuilder = RolesFilter.builder();
|
||||
|
||||
if (queryParameters != null)
|
||||
{
|
||||
var propertyWalker = new RolesQueryWalker();
|
||||
QueryHelper.walk(queryParameters, propertyWalker);
|
||||
|
||||
rolesFilterBuilder
|
||||
.withPersonId(propertyWalker.getPersonId())
|
||||
.withCapabilities(propertyWalker.getCapabilitiesNames())
|
||||
.withIncludeSystemRoles(propertyWalker.includeSystemRoles());
|
||||
}
|
||||
return rolesFilterBuilder.build();
|
||||
}
|
||||
|
||||
private static class RolesQueryWalker extends MapBasedQueryWalker
|
||||
{
|
||||
private List<String> capabilitiesNames;
|
||||
|
||||
public RolesQueryWalker()
|
||||
{
|
||||
super(LIST_ROLES_QUERY_PROPERTIES, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void in(String propertyName, boolean negated, String... propertyValues)
|
||||
{
|
||||
if (negated)
|
||||
{
|
||||
throw new InvalidArgumentException("Cannot use NOT for " + propertyName);
|
||||
}
|
||||
|
||||
if (PARAM_CAPABILITY_NAME.equalsIgnoreCase(propertyName))
|
||||
{
|
||||
capabilitiesNames = Arrays.asList(propertyValues);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void and()
|
||||
{
|
||||
// allow AND, e.g. personId='123' AND includeSystemRoles=true
|
||||
}
|
||||
|
||||
public List<String> getCapabilitiesNames()
|
||||
{
|
||||
return this.capabilitiesNames;
|
||||
}
|
||||
|
||||
public String getPersonId()
|
||||
{
|
||||
return getProperty(PARAM_PERSON_ID, WhereClauseParser.EQUALS, String.class);
|
||||
}
|
||||
|
||||
public Boolean includeSystemRoles()
|
||||
{
|
||||
return getProperty(PARAM_INCLUDE_SYSTEM_ROLES, WhereClauseParser.EQUALS, Boolean.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RolesFilter
|
||||
{
|
||||
private String personId;
|
||||
private boolean includeSystemRoles;
|
||||
private List<String> capabilities;
|
||||
|
||||
private RolesFilter()
|
||||
{}
|
||||
|
||||
public static RolesFilterBuilder builder()
|
||||
{
|
||||
return new RolesFilterBuilder();
|
||||
}
|
||||
|
||||
public String getPersonId()
|
||||
{
|
||||
return personId;
|
||||
}
|
||||
|
||||
public boolean includeSystemRoles()
|
||||
{
|
||||
return includeSystemRoles;
|
||||
}
|
||||
|
||||
public List<String> getCapabilities()
|
||||
{
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public static class RolesFilterBuilder
|
||||
{
|
||||
private String personId;
|
||||
private boolean includeSystemRoles = true;
|
||||
private List<String> capabilities;
|
||||
|
||||
public RolesFilterBuilder withPersonId(String personId)
|
||||
{
|
||||
this.personId = personId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RolesFilterBuilder withIncludeSystemRoles(Boolean includeSystemRoles)
|
||||
{
|
||||
if (includeSystemRoles != null)
|
||||
{
|
||||
this.includeSystemRoles = includeSystemRoles;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public RolesFilterBuilder withCapabilities(List<String> capabilities)
|
||||
{
|
||||
this.capabilities = capabilities;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RolesFilter build()
|
||||
{
|
||||
RolesFilter rolesFilter = new RolesFilter();
|
||||
rolesFilter.personId = this.personId;
|
||||
rolesFilter.includeSystemRoles = this.includeSystemRoles;
|
||||
rolesFilter.capabilities = this.capabilities;
|
||||
return rolesFilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api.model;
|
||||
|
||||
public record CapabilityModel(String name, String title, String description, GroupModel group, int index)
|
||||
{}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api.model;
|
||||
|
||||
public record GroupModel(String id, String title)
|
||||
{}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record RoleModel(String name, String displayLabel, List<CapabilityModel> capabilities, String roleGroupName, String groupShortName, List<String> assignedUsers, List<String> assignedGroups)
|
||||
{}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record RoleModelList(List<RoleModel> roleModelList)
|
||||
{}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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 info that defines the Information Governance Roles REST API
|
||||
*
|
||||
* @author Damian Ujma
|
||||
*/
|
||||
@WebApi(name = "gs", scope = Api.SCOPE.PUBLIC, version = 1)
|
||||
package org.alfresco.rm.rest.api.roles;
|
||||
|
||||
import org.alfresco.rest.framework.Api;
|
||||
import org.alfresco.rest.framework.WebApi;
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.rm.rest.api.impl;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
|
||||
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.role.Role;
|
||||
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
|
||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||
import org.alfresco.rest.framework.resource.parameters.Paging;
|
||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
|
||||
import org.alfresco.rm.rest.api.model.CapabilityModel;
|
||||
import org.alfresco.rm.rest.api.model.RoleModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class RMRolesImplUnitTest extends BaseUnitTest {
|
||||
|
||||
private final RecognizedParamsExtractor queryExtractor = new RecognizedParamsExtractor() {};
|
||||
|
||||
private RMRolesImpl rmRolesImpl;
|
||||
private FilePlanRoleService mockedFilePlanRoleService;
|
||||
private ApiNodesModelFactory mockedNodesModelFactory;
|
||||
|
||||
private final Capability viewRecordsCapability = mock(Capability.class);
|
||||
private final Capability editMetadataCapability = mock(Capability.class);
|
||||
|
||||
private final Role role1 = new Role("Role1", "Role 1", Set.of(viewRecordsCapability), "Group1");
|
||||
private final Role role2 = new Role("Role2", "Role 2", Set.of(editMetadataCapability), "Group2");
|
||||
|
||||
private final RoleModel roleModel1 = new RoleModel("Role1", "Role 1", List.of(new CapabilityModel("ViewRecords", "", "", null, 0)), "Group1", null, List.of("User1"), List.of("Group1"));
|
||||
private final RoleModel roleModel2 = new RoleModel("Role2", "Role 2", List.of(new CapabilityModel("EditMetadata", "", "", null, 0)), "Group2", null, List.of("User2"), List.of("Group2"));
|
||||
|
||||
private final NodeRef filePlan = new NodeRef("workspace://SpacesStore/testFilePlan");
|
||||
|
||||
private final Parameters parameters = mock(Parameters.class);
|
||||
private final Paging paging = mock(Paging.class);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mockedFilePlanRoleService = mock(FilePlanRoleService.class);
|
||||
mockedNodesModelFactory = mock(ApiNodesModelFactory.class);
|
||||
|
||||
rmRolesImpl = new RMRolesImpl();
|
||||
rmRolesImpl.setFilePlanRoleService(mockedFilePlanRoleService);
|
||||
rmRolesImpl.setNodesModelFactory(mockedNodesModelFactory);
|
||||
|
||||
when(mockedFilePlanRoleService.getRoles(filePlan, true)).thenReturn(Set.of(role1, role2));
|
||||
when(mockedNodesModelFactory.createRoleModel(eq(role1), any(), any())).thenReturn(roleModel1);
|
||||
when(mockedNodesModelFactory.createRoleModel(eq(role2), any(), any())).thenReturn(roleModel2);
|
||||
|
||||
when(viewRecordsCapability.getName()).thenReturn("ViewRecords");
|
||||
when(editMetadataCapability.getName()).thenReturn("EditMetadata");
|
||||
|
||||
when(parameters.getPaging()).thenReturn(paging);
|
||||
when(paging.getSkipCount()).thenReturn(0);
|
||||
when(paging.getMaxItems()).thenReturn(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRoles_NoFilters() {
|
||||
// when
|
||||
CollectionWithPagingInfo<RoleModel> result = rmRolesImpl.getRoles(filePlan, parameters);
|
||||
|
||||
// then
|
||||
List<RoleModel> roleModelList = (List<RoleModel>) result.getCollection();
|
||||
assertEquals(2, (int) result.getTotalItems());
|
||||
assertEquals(List.of(roleModel1, roleModel2), roleModelList);
|
||||
verify(mockedFilePlanRoleService).getRoles(filePlan, true);
|
||||
verify(mockedNodesModelFactory).createRoleModel(eq(role1), any(), any());
|
||||
verify(mockedNodesModelFactory).createRoleModel(eq(role2), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRoles_WithPersonId() {
|
||||
// given
|
||||
String personId = "testUser";
|
||||
when(mockedFilePlanRoleService.getRolesByUser(filePlan, personId, true)).thenReturn(Set.of(role1));
|
||||
when(parameters.getQuery()).thenReturn(queryExtractor.getWhereClause("(personId='" + personId + "')"));
|
||||
|
||||
// when
|
||||
CollectionWithPagingInfo<RoleModel> result = rmRolesImpl.getRoles(filePlan, parameters);
|
||||
|
||||
// then
|
||||
assertEquals(1, (int) result.getTotalItems());
|
||||
assertEquals(List.of(roleModel1), result.getCollection());
|
||||
verify(mockedFilePlanRoleService).getRolesByUser(filePlan, personId, true);
|
||||
verify(mockedNodesModelFactory).createRoleModel(eq(role1), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNonSystemRoles() {
|
||||
//given
|
||||
when(mockedFilePlanRoleService.getRoles(filePlan, false)).thenReturn(Set.of(role2));
|
||||
when(parameters.getQuery()).thenReturn(queryExtractor.getWhereClause("(systemRoles=false)"));
|
||||
|
||||
// when
|
||||
CollectionWithPagingInfo<RoleModel> result = rmRolesImpl.getRoles(filePlan, parameters);
|
||||
|
||||
// then
|
||||
assertEquals(1, (int) result.getTotalItems());
|
||||
assertEquals(List.of(roleModel2), result.getCollection());
|
||||
verify(mockedFilePlanRoleService).getRoles(filePlan, false);
|
||||
verify(mockedNodesModelFactory).createRoleModel(eq(role2), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRoles_WithCapabilitiesFilter() {
|
||||
// given
|
||||
when(parameters.getQuery()).thenReturn(queryExtractor.getWhereClause("(capabilityName IN ('ViewRecords'))"));
|
||||
|
||||
// when
|
||||
CollectionWithPagingInfo<RoleModel> result = rmRolesImpl.getRoles(filePlan, parameters);
|
||||
|
||||
// then
|
||||
assertEquals(1, (int) result.getTotalItems());
|
||||
assertEquals(List.of(roleModel1), result.getCollection());
|
||||
verify(mockedFilePlanRoleService).getRoles(filePlan, true);
|
||||
verify(mockedNodesModelFactory).createRoleModel(eq(role1), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRoles_IncludeAssignedUsersAndGroups() {
|
||||
// given
|
||||
when(mockedFilePlanRoleService.getRoles(filePlan, true)).thenReturn(Set.of(role1));
|
||||
when(mockedFilePlanRoleService.getAllAssignedToRole(filePlan, "Role1")).thenReturn(Set.of("User1"));
|
||||
when(mockedFilePlanRoleService.getGroupsAssignedToRole(filePlan, "Role1")).thenReturn(Set.of("Group1"));
|
||||
|
||||
when(parameters.getInclude()).thenReturn(List.of("assignedUsers", "assignedGroups"));
|
||||
|
||||
// when
|
||||
CollectionWithPagingInfo<RoleModel> result = rmRolesImpl.getRoles(filePlan, parameters);
|
||||
|
||||
// then
|
||||
List<RoleModel> roleModelList = (List<RoleModel>) result.getCollection();
|
||||
assertEquals(1, (int) result.getTotalItems());
|
||||
assertEquals(List.of(roleModel1), roleModelList);
|
||||
assertEquals(List.of("User1"), roleModelList.get(0).assignedUsers());
|
||||
assertEquals(List.of("Group1"), roleModelList.get(0).assignedGroups());
|
||||
verify(mockedFilePlanRoleService).getRoles(filePlan, true);
|
||||
verify(mockedFilePlanRoleService).getAllAssignedToRole(filePlan, "Role1");
|
||||
verify(mockedFilePlanRoleService).getGroupsAssignedToRole(filePlan, "Role1");
|
||||
verify(mockedNodesModelFactory).createRoleModel(role1, List.of("User1"), List.of("Group1"));
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -540,6 +540,66 @@ paths:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
'/file-plans/{filePlanId}/roles':
|
||||
get:
|
||||
tags:
|
||||
- file-plans
|
||||
summary: Get roles in a file plan
|
||||
description: |
|
||||
Gets a list of roles for the specified file plan **filePlanId**.
|
||||
|
||||
You can use the **include** parameter to return additional information.
|
||||
|
||||
The **where** parameter can also be used to filter by **personId**, **systemRoles** and **capabilityName**.
|
||||
|
||||
You can use the **where** parameter to
|
||||
* filter roles by user:
|
||||
`where=(personId='admin')`
|
||||
|
||||
* not include system roles in the results:
|
||||
`where=(systemRoles=false)`
|
||||
|
||||
* filter roles by specified capabilities:
|
||||
`where=(capabilityName in ('AddToHold', 'ViewRecords'))`
|
||||
|
||||
This may be combined with all filter, as shown below:
|
||||
|
||||
`where=(systemRoles=false and personId='johndoe' and capabilityName in ('AddToHold', 'ViewRecords'))`
|
||||
|
||||
operationId: getFilePlanRoles
|
||||
parameters:
|
||||
- $ref: '#/parameters/filePlanIdWithAliasParam'
|
||||
- $ref: '#/parameters/whereParam'
|
||||
- $ref: '#/parameters/rolesIncludeParam'
|
||||
- $ref: '#/parameters/skipCountParam'
|
||||
- $ref: '#/parameters/maxItemsParam'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
'200':
|
||||
description: Successful response
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
list:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/RoleModel'
|
||||
pagination:
|
||||
$ref: '#/definitions/Pagination'
|
||||
'400':
|
||||
description: |
|
||||
Invalid parameter: value of **maxItems** or **skipCount**, or **include**, or **where** is invalid
|
||||
'401':
|
||||
description: Authentication failed
|
||||
'403':
|
||||
description: Current user does not have permission to read **filePlanId**
|
||||
'404':
|
||||
description: "**filePlanId** does not exist"
|
||||
default:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
## Unfiled records containers
|
||||
'/unfiled-containers/{unfiledContainerId}':
|
||||
get:
|
||||
@@ -3307,6 +3367,21 @@ parameters:
|
||||
* actions
|
||||
required: false
|
||||
type: string
|
||||
rolesIncludeParam:
|
||||
name: include
|
||||
in: query
|
||||
description: |
|
||||
Returns additional information about roles. Any optional field from the response model can be requested. For example:
|
||||
* assignedUsers
|
||||
* assignedGroups
|
||||
required: false
|
||||
type: string
|
||||
whereParam:
|
||||
name: where
|
||||
in: query
|
||||
description: A string to restrict the returned objects by using a predicate.
|
||||
required: false
|
||||
type: string
|
||||
definitions:
|
||||
FilePlanComponentBodyUpdate:
|
||||
type: object
|
||||
@@ -4389,6 +4464,49 @@ definitions:
|
||||
query:
|
||||
description: The query which may have been generated in some way from the userQuery
|
||||
type: string
|
||||
CapabilityModel:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
group:
|
||||
$ref: '#/definitions/GroupModel'
|
||||
index:
|
||||
type: integer
|
||||
GroupModel:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
RoleModel:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
displayLabel:
|
||||
type: string
|
||||
capabilities:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/CapabilityModel'
|
||||
roleGroupName:
|
||||
type: string
|
||||
groupShortName:
|
||||
type: string
|
||||
assignedUsers:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
assignedGroups:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
HoldBulkOperation:
|
||||
type: object
|
||||
properties:
|
||||
@@ -4929,4 +5047,4 @@ definitions:
|
||||
- SiteConsumer
|
||||
- SiteCollaborator
|
||||
- SiteContributor
|
||||
- SiteManager
|
||||
- SiteManager
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -80,6 +80,11 @@ function runAction(p_params)
|
||||
{
|
||||
result.fileExist = true;
|
||||
}
|
||||
if (error.indexOf("FolderExistsException") != -1)
|
||||
{
|
||||
result.fileExist = true;
|
||||
result.type = "folder";
|
||||
}
|
||||
}
|
||||
|
||||
results.push(result);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -49,5 +49,6 @@ then
|
||||
echo "Docker Compose started ok"
|
||||
else
|
||||
echo "Docker Compose failed to start" >&2
|
||||
docker compose ${DOCKER_COMPOSES} logs --tail 200
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<organization>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -747,7 +747,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
restClient.assertStatusCodeIs(NOT_FOUND);
|
||||
restClient.assertLastError().containsSummary("The entity with id: non-existent-node was not found");
|
||||
restClient.assertLastError().containsSummary("Destination folder having Id: non-existent-node no longer exists. Please update your rule definition.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<!-- Resource defaultTransactionIsolation="-1" defaultAutoCommit="false" maxActive="100" initialSize="10" password="alfresco" username="alfresco" url="jdbc:mysql:///alfresco" driverClassName="org.gjt.mm.mysql.Driver" type="javax.sql.DataSource" auth="Container" name="jdbc/dataSource"/-->
|
||||
<Environment override="false" type="java.lang.Boolean" name="properties/startup.enable" description="A flag that globally enables or disables startup of the major Alfresco subsystems." value="true"/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/dir.root" description="The filesystem directory below which content and index data is stored. Should be on a shared disk if this is a clustered installation."/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.dialect" description="The fully qualified name of a org.hibernate.dialect.Dialect subclass that allows Hibernate to generate SQL optimized for a particular relational database. Choose from org.hibernate.dialect.DerbyDialect, org.hibernate.dialect.MySQLInnoDBDialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoOracle9Dialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoSQLServerDialect, org.hibernate.dialect.PostgreSQLDialect"/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.dialect" description="The fully qualified name of a org.hibernate.dialect.Dialect subclass that allows Hibernate to generate SQL optimized for a particular relational database. Choose from org.hibernate.dialect.DerbyDialect, org.hibernate.dialect.MySQLInnoDBDialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoOracle9Dialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect, org.alfresco.repo.domain.hibernate.dialect.SQLServerDialect, org.hibernate.dialect.PostgreSQLDialect"/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.query.substitutions" description="Mapping from tokens in Hibernate queries to SQL tokens. For PostgreSQL, set this to "true TRUE, false FALSE"."/>
|
||||
<Environment override="false" type="java.lang.Boolean" name="properties/hibernate.jdbc.use_get_generated_keys" description="Enable use of JDBC3 PreparedStatement.getGeneratedKeys() to retrieve natively generated keys after insert. Requires JDBC3+ driver. Set to false if your driver has problems with the Hibernate identifier generators. By default, tries to determine the driver capabilities using connection metadata."/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.default_schema" description="Qualify unqualified table names with the given schema/tablespace in generated SQL. It may be necessary to set this when the target database has more than one schema."/>
|
||||
|
||||
@@ -500,7 +500,7 @@
|
||||
org.hibernate.dialect.MySQLInnoDBDialect,
|
||||
org.alfresco.repo.domain.hibernate.dialect.AlfrescoOracle9Dialect,
|
||||
org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect,
|
||||
org.alfresco.repo.domain.hibernate.dialect.AlfrescoSQLServerDialect, org.hibernate.dialect.PostgreSQLDialect</description>
|
||||
org.alfresco.repo.domain.hibernate.dialect.SQLServerDialect, org.hibernate.dialect.PostgreSQLDialect</description>
|
||||
<env-entry-name>properties/hibernate.dialect</env-entry-name>
|
||||
<env-entry-type>java.lang.String</env-entry-type>
|
||||
<env-entry-value/> <!-- Empty value included for JBoss compatibility -->
|
||||
|
||||
21
pom.xml
21
pom.xml
@@ -2,10 +2,11 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Alfresco Community Repo Parent</name>
|
||||
|
||||
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-super-pom</artifactId>
|
||||
@@ -58,7 +59,7 @@
|
||||
|
||||
<dependency.aspectj.version>1.9.22.1</dependency.aspectj.version>
|
||||
<dependency.spring.version>6.2.2</dependency.spring.version>
|
||||
<dependency.spring-security.version>6.3.7</dependency.spring-security.version>
|
||||
<dependency.spring-security.version>6.3.9</dependency.spring-security.version>
|
||||
<dependency.antlr.version>3.5.3</dependency.antlr.version>
|
||||
<dependency.jackson.version>2.17.2</dependency.jackson.version>
|
||||
<dependency.cxf.version>4.1.0</dependency.cxf.version>
|
||||
@@ -74,8 +75,9 @@
|
||||
<dependency.guava.version>33.3.1-jre</dependency.guava.version>
|
||||
<dependency.httpclient.version>4.5.14</dependency.httpclient.version>
|
||||
<dependency.httpcore.version>4.4.16</dependency.httpcore.version>
|
||||
<dependency.httpcomponents-httpclient5.version>5.4.1</dependency.httpcomponents-httpclient5.version>
|
||||
<dependency.httpcomponents-httpcore5.version>5.3.3</dependency.httpcomponents-httpcore5.version>
|
||||
<dependency.httpcomponents-httpclient5.version>5.5</dependency.httpcomponents-httpclient5.version>
|
||||
<dependency.httpcomponents-httpcore5.version>5.3.4</dependency.httpcomponents-httpcore5.version>
|
||||
<dependency.httpcomponents-httpcore5-h2.version>5.3.4</dependency.httpcomponents-httpcore5-h2.version>
|
||||
<dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version>
|
||||
<dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version>
|
||||
<dependency.slf4j.version>2.0.16</dependency.slf4j.version>
|
||||
@@ -83,9 +85,9 @@
|
||||
<dependency.groovy.version>3.0.23</dependency.groovy.version>
|
||||
<dependency.tika.version>2.9.2</dependency.tika.version>
|
||||
<dependency.truezip.version>7.7.10</dependency.truezip.version>
|
||||
<dependency.poi.version>5.3.0</dependency.poi.version>
|
||||
<dependency.poi.version>5.4.0</dependency.poi.version>
|
||||
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
|
||||
<dependency.camel.version>4.6.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
|
||||
<dependency.camel.version>4.11.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
|
||||
<dependency.netty.version>4.1.118.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
|
||||
<dependency.activemq.version>5.18.6</dependency.activemq.version>
|
||||
<dependency.apache-compress.version>1.27.1</dependency.apache-compress.version>
|
||||
@@ -153,7 +155,7 @@
|
||||
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
|
||||
<url>https://github.com/Alfresco/alfresco-community-repo</url>
|
||||
<tag>25.2.0.17</tag>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -400,6 +402,11 @@
|
||||
<artifactId>httpcore5</artifactId>
|
||||
<version>${dependency.httpcomponents-httpcore5.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.core5</groupId>
|
||||
<artifactId>httpcore5-h2</artifactId>
|
||||
<version>${dependency.httpcomponents-httpcore5-h2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -46,7 +46,7 @@ import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.external.AdminConsoleAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.external.ExternalUserAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.external.RemoteUserMapper;
|
||||
import org.alfresco.repo.web.auth.AuthenticationListener;
|
||||
import org.alfresco.repo.web.auth.TicketCredentials;
|
||||
@@ -71,9 +71,11 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
|
||||
protected RemoteUserMapper remoteUserMapper;
|
||||
protected AuthenticationComponent authenticationComponent;
|
||||
protected AdminConsoleAuthenticator adminConsoleAuthenticator;
|
||||
protected ExternalUserAuthenticator adminConsoleAuthenticator;
|
||||
protected ExternalUserAuthenticator webScriptsHomeAuthenticator;
|
||||
|
||||
private boolean alwaysAllowBasicAuthForAdminConsole = true;
|
||||
private boolean alwaysAllowBasicAuthForWebScriptsHome = true;
|
||||
List<String> adminConsoleScriptFamilies;
|
||||
long getRemoteUserTimeoutMilliseconds = GET_REMOTE_USER_TIMEOUT_MILLISECONDS_DEFAULT;
|
||||
|
||||
@@ -97,6 +99,16 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
this.alwaysAllowBasicAuthForAdminConsole = alwaysAllowBasicAuthForAdminConsole;
|
||||
}
|
||||
|
||||
public boolean isAlwaysAllowBasicAuthForWebScriptsHome()
|
||||
{
|
||||
return alwaysAllowBasicAuthForWebScriptsHome;
|
||||
}
|
||||
|
||||
public void setAlwaysAllowBasicAuthForWebScriptsHome(boolean alwaysAllowBasicAuthForWebScriptsHome)
|
||||
{
|
||||
this.alwaysAllowBasicAuthForWebScriptsHome = alwaysAllowBasicAuthForWebScriptsHome;
|
||||
}
|
||||
|
||||
public List<String> getAdminConsoleScriptFamilies()
|
||||
{
|
||||
return adminConsoleScriptFamilies;
|
||||
@@ -118,11 +130,17 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
}
|
||||
|
||||
public void setAdminConsoleAuthenticator(
|
||||
AdminConsoleAuthenticator adminConsoleAuthenticator)
|
||||
ExternalUserAuthenticator adminConsoleAuthenticator)
|
||||
{
|
||||
this.adminConsoleAuthenticator = adminConsoleAuthenticator;
|
||||
}
|
||||
|
||||
public void setWebScriptsHomeAuthenticator(
|
||||
ExternalUserAuthenticator webScriptsHomeAuthenticator)
|
||||
{
|
||||
this.webScriptsHomeAuthenticator = webScriptsHomeAuthenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res)
|
||||
{
|
||||
@@ -136,6 +154,8 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
*/
|
||||
public class RemoteUserAuthenticator extends BasicHttpAuthenticator
|
||||
{
|
||||
private static final String WEB_SCRIPTS_BASE_PATH = "org/springframework/extensions/webscripts";
|
||||
|
||||
public RemoteUserAuthenticator(WebScriptServletRequest req, WebScriptServletResponse res, AuthenticationListener listener)
|
||||
{
|
||||
super(req, res, listener);
|
||||
@@ -156,24 +176,47 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
{
|
||||
|
||||
if (servletReq.getServiceMatch() != null &&
|
||||
isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
|
||||
isAdminConsole(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
|
||||
{
|
||||
userId = getAdminConsoleUser();
|
||||
}
|
||||
else if (servletReq.getServiceMatch() != null &&
|
||||
isWebScriptsHome(servletReq.getServiceMatch().getWebScript()) && isWebScriptsHomeAuthenticatorActive())
|
||||
{
|
||||
userId = getWebScriptsHomeUser();
|
||||
}
|
||||
|
||||
if (userId == null)
|
||||
{
|
||||
if (isAlwaysAllowBasicAuthForAdminConsole())
|
||||
{
|
||||
final boolean useTimeoutForAdminAccessingAdminConsole = shouldUseTimeoutForAdminAccessingAdminConsole(required, isGuest);
|
||||
boolean shouldUseTimeout = shouldUseTimeoutForAdminAccessingAdminConsole(required, isGuest);
|
||||
|
||||
if (useTimeoutForAdminAccessingAdminConsole && isBasicAuthHeaderPresentForAdmin())
|
||||
if (shouldUseTimeout && isBasicAuthHeaderPresentForAdmin())
|
||||
{
|
||||
return callBasicAuthForAdminConsoleAccess(required, isGuest);
|
||||
return callBasicAuthForAdminConsoleOrWebScriptsHomeAccess(required, isGuest);
|
||||
}
|
||||
try
|
||||
{
|
||||
userId = getRemoteUserWithTimeout(useTimeoutForAdminAccessingAdminConsole);
|
||||
userId = getRemoteUserWithTimeout(shouldUseTimeout);
|
||||
}
|
||||
catch (AuthenticationTimeoutException e)
|
||||
{
|
||||
// return basic auth challenge
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (isAlwaysAllowBasicAuthForWebScriptsHome())
|
||||
{
|
||||
boolean shouldUseTimeout = shouldUseTimeoutForAdminAccessingWebScriptsHome(required, isGuest);
|
||||
|
||||
if (shouldUseTimeout && isBasicAuthHeaderPresentForAdmin())
|
||||
{
|
||||
return callBasicAuthForAdminConsoleOrWebScriptsHomeAccess(required, isGuest);
|
||||
}
|
||||
try
|
||||
{
|
||||
userId = getRemoteUserWithTimeout(shouldUseTimeout);
|
||||
}
|
||||
catch (AuthenticationTimeoutException e)
|
||||
{
|
||||
@@ -252,38 +295,63 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
authenticated = super.authenticate(required, isGuest);
|
||||
}
|
||||
}
|
||||
if (!authenticated && servletReq.getServiceMatch() != null &&
|
||||
isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
|
||||
if (!authenticated && servletReq.getServiceMatch() != null)
|
||||
{
|
||||
adminConsoleAuthenticator.requestAuthentication(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
WebScript webScript = servletReq.getServiceMatch().getWebScript();
|
||||
|
||||
if (isAdminConsole(webScript) && isAdminConsoleAuthenticatorActive())
|
||||
{
|
||||
adminConsoleAuthenticator.requestAuthentication(
|
||||
this.servletReq.getHttpServletRequest(),
|
||||
this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
else if (isWebScriptsHome(webScript)
|
||||
&& isWebScriptsHomeAuthenticatorActive())
|
||||
{
|
||||
webScriptsHomeAuthenticator.requestAuthentication(
|
||||
this.servletReq.getHttpServletRequest(),
|
||||
this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
}
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
private boolean callBasicAuthForAdminConsoleAccess(RequiredAuthentication required, boolean isGuest)
|
||||
private boolean callBasicAuthForAdminConsoleOrWebScriptsHomeAccess(RequiredAuthentication required, boolean isGuest)
|
||||
{
|
||||
// return REST call, after a timeout/basic auth challenge
|
||||
if (LOGGER.isTraceEnabled())
|
||||
{
|
||||
LOGGER.trace("An Admin Console request has come in with Basic Auth headers present for an admin user.");
|
||||
LOGGER.trace("An Admin Console or WebScripts Home request has come in with Basic Auth headers present for an admin user.");
|
||||
}
|
||||
// In order to prompt for another password, in case it was not entered correctly,
|
||||
// the output of this method should be returned by the calling "authenticate" method;
|
||||
// This would also mean, that once the admin basic auth header is present,
|
||||
// the authentication chain will not be used for the admin console access
|
||||
// the authentication chain will not be used for access
|
||||
return super.authenticate(required, isGuest);
|
||||
}
|
||||
|
||||
private boolean shouldUseTimeoutForAdminAccessingAdminConsole(RequiredAuthentication required, boolean isGuest)
|
||||
{
|
||||
boolean useTimeoutForAdminAccessingAdminConsole = RequiredAuthentication.admin.equals(required) && !isGuest &&
|
||||
servletReq.getServiceMatch() != null && isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript());
|
||||
boolean adminConsoleTimeout = RequiredAuthentication.admin.equals(required) && !isGuest &&
|
||||
servletReq.getServiceMatch() != null && isAdminConsole(servletReq.getServiceMatch().getWebScript());
|
||||
|
||||
if (LOGGER.isTraceEnabled())
|
||||
{
|
||||
LOGGER.trace("Should ensure that the admins can login with basic auth: " + useTimeoutForAdminAccessingAdminConsole);
|
||||
LOGGER.trace("Should ensure that the admins can login with basic auth: " + adminConsoleTimeout);
|
||||
}
|
||||
return useTimeoutForAdminAccessingAdminConsole;
|
||||
return adminConsoleTimeout;
|
||||
}
|
||||
|
||||
private boolean shouldUseTimeoutForAdminAccessingWebScriptsHome(RequiredAuthentication required, boolean isGuest)
|
||||
{
|
||||
boolean adminWebScriptsHomeTimeout = RequiredAuthentication.admin.equals(required) && !isGuest &&
|
||||
servletReq.getServiceMatch() != null && isWebScriptsHome(servletReq.getServiceMatch().getWebScript());
|
||||
|
||||
if (LOGGER.isTraceEnabled())
|
||||
{
|
||||
LOGGER.trace("Should ensure that the admins can login with basic auth: " + adminWebScriptsHomeTimeout);
|
||||
}
|
||||
return adminWebScriptsHomeTimeout;
|
||||
}
|
||||
|
||||
private boolean isRemoteUserMapperActive()
|
||||
@@ -296,7 +364,12 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
return adminConsoleAuthenticator != null && (!(adminConsoleAuthenticator instanceof ActivateableBean) || ((ActivateableBean) adminConsoleAuthenticator).isActive());
|
||||
}
|
||||
|
||||
protected boolean isAdminConsoleWebScript(WebScript webScript)
|
||||
private boolean isWebScriptsHomeAuthenticatorActive()
|
||||
{
|
||||
return webScriptsHomeAuthenticator != null && (!(webScriptsHomeAuthenticator instanceof ActivateableBean) || ((ActivateableBean) webScriptsHomeAuthenticator).isActive());
|
||||
}
|
||||
|
||||
protected boolean isAdminConsole(WebScript webScript)
|
||||
{
|
||||
if (webScript == null || adminConsoleScriptFamilies == null || webScript.getDescription() == null
|
||||
|| webScript.getDescription().getFamilys() == null)
|
||||
@@ -310,7 +383,7 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
}
|
||||
|
||||
// intersect the "family" sets defined
|
||||
Set<String> families = new HashSet<String>(webScript.getDescription().getFamilys());
|
||||
Set<String> families = new HashSet<>(webScript.getDescription().getFamilys());
|
||||
families.retainAll(adminConsoleScriptFamilies);
|
||||
final boolean isAdminConsole = !families.isEmpty();
|
||||
|
||||
@@ -322,6 +395,23 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
return isAdminConsole;
|
||||
}
|
||||
|
||||
protected boolean isWebScriptsHome(WebScript webScript)
|
||||
{
|
||||
if (webScript == null || webScript.toString() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isWebScriptsHome = webScript.toString().startsWith(WEB_SCRIPTS_BASE_PATH);
|
||||
|
||||
if (LOGGER.isTraceEnabled() && isWebScriptsHome)
|
||||
{
|
||||
LOGGER.trace("Detected a WebScripts Home webscript: " + webScript);
|
||||
}
|
||||
|
||||
return isWebScriptsHome;
|
||||
}
|
||||
|
||||
protected String getRemoteUserWithTimeout(boolean useTimeout) throws AuthenticationTimeoutException
|
||||
{
|
||||
if (!useTimeout)
|
||||
@@ -417,7 +507,21 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
|
||||
if (isRemoteUserMapperActive())
|
||||
{
|
||||
userId = adminConsoleAuthenticator.getAdminConsoleUser(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
userId = adminConsoleAuthenticator.getUserId(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
|
||||
logRemoteUserID(userId);
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
protected String getWebScriptsHomeUser()
|
||||
{
|
||||
String userId = null;
|
||||
|
||||
if (isRemoteUserMapperActive())
|
||||
{
|
||||
userId = webScriptsHomeAuthenticator.getUserId(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
|
||||
logRemoteUserID(userId);
|
||||
|
||||
@@ -712,7 +712,7 @@ public class PeopleImpl implements People
|
||||
Boolean isEnabled = person.isEnabled();
|
||||
if (isEnabled != null)
|
||||
{
|
||||
if (isAdminAuthority(personIdToUpdate))
|
||||
if (!isEnabled && isAdminAuthority(personIdToUpdate))
|
||||
{
|
||||
throw new PermissionDeniedException("Admin authority cannot be disabled.");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -75,6 +75,7 @@ public class ActionNodeParameterValidator implements ActionValidator
|
||||
static final String NO_PROPER_PERMISSIONS_FOR_NODE = "No proper permissions for node: ";
|
||||
static final String NOT_A_CATEGORY = "Node is not a category ";
|
||||
static final String NOT_A_FOLDER = "Node is not a folder ";
|
||||
static final String NO_LONGER_EXISTS = "%s having Id: %s no longer exists. Please update your rule definition.";
|
||||
|
||||
private final Actions actions;
|
||||
private final NamespaceService namespaceService;
|
||||
@@ -132,7 +133,15 @@ public class ActionNodeParameterValidator implements ActionValidator
|
||||
.filter(pd -> action.getParams().containsKey(pd.getName()))
|
||||
.forEach(p -> {
|
||||
final String nodeId = Objects.toString(action.getParams().get(p.getName()), Strings.EMPTY);
|
||||
final NodeRef nodeRef = nodes.validateNode(nodeId);
|
||||
NodeRef nodeRef;
|
||||
try
|
||||
{
|
||||
nodeRef = nodes.validateNode(nodeId);
|
||||
}
|
||||
catch (EntityNotFoundException e)
|
||||
{
|
||||
throw new EntityNotFoundException(String.format(NO_LONGER_EXISTS, p.getDisplayLabel(), nodeId), e);
|
||||
}
|
||||
validatePermission(action.getActionDefinitionId(), p.getName(), nodeRef);
|
||||
validateType(action.getActionDefinitionId(), nodeRef);
|
||||
});
|
||||
@@ -169,4 +178,5 @@ public class ActionNodeParameterValidator implements ActionValidator
|
||||
throw new InvalidArgumentException(NOT_A_CATEGORY + nodeRef.getId());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly">required</transaction>
|
||||
<lifecycle>internal</lifecycle>
|
||||
</webscript>
|
||||
</webscript>
|
||||
|
||||
@@ -214,9 +214,13 @@
|
||||
<property name="authenticationListener" ref="webScriptAuthenticationListener"/>
|
||||
<property name="remoteUserMapper" ref="RemoteUserMapper" />
|
||||
<property name="adminConsoleAuthenticator" ref="AdminConsoleAuthenticator" />
|
||||
<property name="webScriptsHomeAuthenticator" ref="WebScriptsHomeAuthenticator" />
|
||||
<property name="alwaysAllowBasicAuthForAdminConsole">
|
||||
<value>${authentication.alwaysAllowBasicAuthForAdminConsole.enabled}</value>
|
||||
</property>
|
||||
<property name="alwaysAllowBasicAuthForWebScriptsHome">
|
||||
<value>${authentication.alwaysAllowBasicAuthForWebScriptsHome.enabled}</value>
|
||||
</property>
|
||||
<property name="getRemoteUserTimeoutMilliseconds">
|
||||
<value>${authentication.getRemoteUserTimeoutMilliseconds}</value>
|
||||
</property>
|
||||
|
||||
@@ -205,7 +205,7 @@ public class ProcessesImplTest extends TestCase implements RecognizedParamsExtra
|
||||
{
|
||||
// the tests are always run on PostgreSQL only
|
||||
// Dialect dialect = (Dialect) applicationContext.getBean("dialect");
|
||||
// if (dialect instanceof AlfrescoSQLServerDialect)
|
||||
// if (dialect instanceof SQLServerDialect)
|
||||
// {
|
||||
// REPO-1104: we do not run this test on MS SQL server because it will fail
|
||||
// until the Activiti defect related to REPO-1104 will be fixed
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>25.2.0.17</version>
|
||||
<version>25.2.0.42-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -58,6 +58,7 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FolderExistsException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
@@ -366,7 +367,11 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// TODO: add failed file info to status message?
|
||||
throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
|
||||
if (e.getType().equalsIgnoreCase("folder"))
|
||||
{
|
||||
throw new FolderExistsException(root, file.getName());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,13 +63,7 @@ import org.alfresco.repo.security.permissions.PermissionCheckedValue.PermissionC
|
||||
import org.alfresco.service.Auditable;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileFolderServiceType;
|
||||
import org.alfresco.service.cmr.model.FileFolderUtil;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.model.SubFolderFilter;
|
||||
import org.alfresco.service.cmr.model.*;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
@@ -1314,7 +1308,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
catch (DuplicateChildNodeNameException e)
|
||||
{
|
||||
throw new FileExistsException(parentNodeRef, name);
|
||||
throw new FileExistsException(parentNodeRef, name, typeQName.getLocalName());
|
||||
}
|
||||
|
||||
NodeRef nodeRef = assocRef.getChildRef();
|
||||
|
||||
@@ -31,12 +31,12 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
|
||||
/**
|
||||
* A default {@link AdminConsoleAuthenticator} implementation. Returns null to request a basic auth challenge.
|
||||
* A default {@link ExternalUserAuthenticator} implementation. Returns null to request a basic auth challenge.
|
||||
*/
|
||||
public class DefaultAdminConsoleAuthenticator implements AdminConsoleAuthenticator, ActivateableBean
|
||||
public class DefaultAdminConsoleAuthenticator implements ExternalUserAuthenticator, ActivateableBean
|
||||
{
|
||||
@Override
|
||||
public String getAdminConsoleUser(HttpServletRequest request, HttpServletResponse response)
|
||||
public String getUserId(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.authentication.external;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
|
||||
/**
|
||||
* A default {@link ExternalUserAuthenticator} implementation. Returns null to request a basic auth challenge.
|
||||
*/
|
||||
public class DefaultWebScriptsHomeAuthenticator implements ExternalUserAuthenticator, ActivateableBean
|
||||
{
|
||||
@Override
|
||||
public String getUserId(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
// No implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -29,28 +29,17 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* An interface for objects capable of extracting an externally authenticated user ID from the HTTP Admin Console webscript request.
|
||||
* An interface for objects capable of extracting an externally authenticated user ID from the HTTP request.
|
||||
*/
|
||||
public interface AdminConsoleAuthenticator
|
||||
public interface ExternalUserAuthenticator
|
||||
{
|
||||
/**
|
||||
* Gets an externally authenticated user ID from the HTTP Admin Console webscript request.
|
||||
*
|
||||
* @param request
|
||||
* the request
|
||||
* @param response
|
||||
* the response
|
||||
* Gets an externally authenticated user ID from the HTTP request.
|
||||
*
|
||||
* @return the user ID or <code>null</code> if the user is unauthenticated
|
||||
*/
|
||||
String getAdminConsoleUser(HttpServletRequest request, HttpServletResponse response);
|
||||
String getUserId(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* Requests an authentication.
|
||||
*
|
||||
* @param request
|
||||
* the request
|
||||
* @param response
|
||||
* the response
|
||||
*/
|
||||
/* Sends redirect to external site to initiate the OIDC authorization code flow. */
|
||||
void requestAuthentication(HttpServletRequest request, HttpServletResponse response);
|
||||
}
|
||||
@@ -76,6 +76,18 @@ public class IdentityServiceConfig
|
||||
private String lastNameAttribute;
|
||||
private String emailAttribute;
|
||||
private long jwtClockSkewMs;
|
||||
private String webScriptsHomeRedirectPath;
|
||||
private String webScriptsHomeScopes;
|
||||
|
||||
public String getWebScriptsHomeRedirectPath()
|
||||
{
|
||||
return webScriptsHomeRedirectPath;
|
||||
}
|
||||
|
||||
public void setWebScriptsHomeRedirectPath(String webScriptsHomeRedirectPath)
|
||||
{
|
||||
this.webScriptsHomeRedirectPath = webScriptsHomeRedirectPath;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -359,6 +371,18 @@ public class IdentityServiceConfig
|
||||
this.adminConsoleScopes = adminConsoleScopes;
|
||||
}
|
||||
|
||||
public Set<String> getWebScriptsHomeScopes()
|
||||
{
|
||||
return Stream.of(webScriptsHomeScopes.split(","))
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
public void setWebScriptsHomeScopes(String webScriptsHomeScopes)
|
||||
{
|
||||
this.webScriptsHomeScopes = webScriptsHomeScopes;
|
||||
}
|
||||
|
||||
public Set<String> getPasswordGrantScopes()
|
||||
{
|
||||
return Stream.of(passwordGrantScopes.split(","))
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.identityservice.admin;
|
||||
package org.alfresco.repo.security.authentication.identityservice.authentication;
|
||||
|
||||
import static org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AuthorizationGrant.authorizationCode;
|
||||
import static org.alfresco.repo.security.authentication.identityservice.IdentityServiceMetadataKey.SCOPES_SUPPORTED;
|
||||
@@ -32,7 +32,6 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -50,9 +49,8 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.repo.security.authentication.external.AdminConsoleAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.external.ExternalUserAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.external.RemoteUserMapper;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceConfig;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade;
|
||||
@@ -60,27 +58,26 @@ import org.alfresco.repo.security.authentication.identityservice.IdentityService
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AuthorizationException;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AuthorizationGrant;
|
||||
|
||||
/**
|
||||
* An {@link AdminConsoleAuthenticator} implementation to extract an externally authenticated user ID or to initiate the OIDC authorization code flow.
|
||||
*/
|
||||
public class IdentityServiceAdminConsoleAuthenticator implements AdminConsoleAuthenticator, ActivateableBean
|
||||
public abstract class AbstractIdentityServiceAuthenticator implements ExternalUserAuthenticator
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IdentityServiceAdminConsoleAuthenticator.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractIdentityServiceAuthenticator.class);
|
||||
|
||||
private static final String ALFRESCO_ACCESS_TOKEN = "ALFRESCO_ACCESS_TOKEN";
|
||||
private static final String ALFRESCO_REFRESH_TOKEN = "ALFRESCO_REFRESH_TOKEN";
|
||||
private static final String ALFRESCO_TOKEN_EXPIRATION = "ALFRESCO_TOKEN_EXPIRATION";
|
||||
|
||||
private IdentityServiceConfig identityServiceConfig;
|
||||
private IdentityServiceFacade identityServiceFacade;
|
||||
private AdminConsoleAuthenticationCookiesService cookiesService;
|
||||
private RemoteUserMapper remoteUserMapper;
|
||||
private boolean isEnabled;
|
||||
protected IdentityServiceConfig identityServiceConfig;
|
||||
protected IdentityServiceFacade identityServiceFacade;
|
||||
protected AdminAuthenticationCookiesService cookiesService;
|
||||
protected RemoteUserMapper remoteUserMapper;
|
||||
|
||||
protected abstract String getConfiguredRedirectPath();
|
||||
|
||||
protected abstract Set<String> getConfiguredScopes();
|
||||
|
||||
@Override
|
||||
public String getAdminConsoleUser(HttpServletRequest request, HttpServletResponse response)
|
||||
public String getUserId(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
// Try to extract username from the authorization header
|
||||
String username = remoteUserMapper.getRemoteUser(request);
|
||||
if (username != null)
|
||||
{
|
||||
@@ -107,16 +104,12 @@ public class IdentityServiceAdminConsoleAuthenticator implements AdminConsoleAut
|
||||
return null;
|
||||
}
|
||||
|
||||
return remoteUserMapper.getRemoteUser(decorateBearerHeader(bearerToken, request));
|
||||
HttpServletRequest wrappedRequest = newRequestWrapper(Map.of("Authorization", "Bearer " + bearerToken), request);
|
||||
return remoteUserMapper.getRemoteUser(wrappedRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
respondWithAuthChallenge(request, response);
|
||||
}
|
||||
|
||||
private void respondWithAuthChallenge(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -124,7 +117,8 @@ public class IdentityServiceAdminConsoleAuthenticator implements AdminConsoleAut
|
||||
{
|
||||
LOGGER.debug("Responding with the authentication challenge");
|
||||
}
|
||||
response.sendRedirect(getAuthenticationRequest(request));
|
||||
String authenticationRequest = buildAuthRequestUrl(request);
|
||||
response.sendRedirect(authenticationRequest);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
@@ -133,84 +127,34 @@ public class IdentityServiceAdminConsoleAuthenticator implements AdminConsoleAut
|
||||
}
|
||||
}
|
||||
|
||||
private String retrieveTokenUsingAuthCode(HttpServletRequest request, HttpServletResponse response, String code)
|
||||
protected String getRedirectUri(String requestURL)
|
||||
{
|
||||
String bearerToken = null;
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Retrieving a response using the Authorization Code at the Token Endpoint");
|
||||
}
|
||||
try
|
||||
{
|
||||
AccessTokenAuthorization accessTokenAuthorization = identityServiceFacade.authorize(
|
||||
authorizationCode(code, request.getRequestURL().toString()));
|
||||
addCookies(response, accessTokenAuthorization);
|
||||
bearerToken = accessTokenAuthorization.getAccessToken().getTokenValue();
|
||||
}
|
||||
catch (AuthorizationException exception)
|
||||
{
|
||||
if (LOGGER.isWarnEnabled())
|
||||
{
|
||||
LOGGER.warn(
|
||||
"Error while trying to retrieve a response using the Authorization Code at the Token Endpoint: {}",
|
||||
exception.getMessage());
|
||||
}
|
||||
}
|
||||
return bearerToken;
|
||||
return buildRedirectUri(requestURL, getConfiguredRedirectPath());
|
||||
}
|
||||
|
||||
private String refreshTokenIfNeeded(HttpServletRequest request, HttpServletResponse response, String bearerToken)
|
||||
{
|
||||
String refreshToken = cookiesService.getCookie(ALFRESCO_REFRESH_TOKEN, request);
|
||||
String authTokenExpiration = cookiesService.getCookie(ALFRESCO_TOKEN_EXPIRATION, request);
|
||||
try
|
||||
{
|
||||
if (isAuthTokenExpired(authTokenExpiration))
|
||||
{
|
||||
bearerToken = refreshAuthToken(refreshToken, response);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Error while trying to refresh Auth Token: {}", e.getMessage());
|
||||
}
|
||||
bearerToken = null;
|
||||
resetCookies(response);
|
||||
}
|
||||
return bearerToken;
|
||||
}
|
||||
|
||||
private void addCookies(HttpServletResponse response, AccessTokenAuthorization accessTokenAuthorization)
|
||||
{
|
||||
cookiesService.addCookie(ALFRESCO_ACCESS_TOKEN, accessTokenAuthorization.getAccessToken().getTokenValue(), response);
|
||||
cookiesService.addCookie(ALFRESCO_TOKEN_EXPIRATION, String.valueOf(
|
||||
accessTokenAuthorization.getAccessToken().getExpiresAt().toEpochMilli()), response);
|
||||
cookiesService.addCookie(ALFRESCO_REFRESH_TOKEN, accessTokenAuthorization.getRefreshTokenValue(), response);
|
||||
}
|
||||
|
||||
private String getAuthenticationRequest(HttpServletRequest request)
|
||||
public String buildAuthRequestUrl(HttpServletRequest request)
|
||||
{
|
||||
ClientRegistration clientRegistration = identityServiceFacade.getClientRegistration();
|
||||
State state = new State();
|
||||
|
||||
UriComponentsBuilder authRequestBuilder = UriComponentsBuilder.fromUriString(clientRegistration.getProviderDetails().getAuthorizationUri())
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(clientRegistration.getProviderDetails()
|
||||
.getAuthorizationUri())
|
||||
.queryParam("client_id", clientRegistration.getClientId())
|
||||
.queryParam("redirect_uri", getRedirectUri(request.getRequestURL().toString()))
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("scope", String.join("+", getScopes(clientRegistration)))
|
||||
.queryParam("scope", String.join("+", getConfiguredScopes(clientRegistration)))
|
||||
.queryParam("state", state.toString());
|
||||
|
||||
if (StringUtils.isNotBlank(identityServiceConfig.getAudience()))
|
||||
{
|
||||
authRequestBuilder.queryParam("audience", identityServiceConfig.getAudience());
|
||||
builder.queryParam("audience", identityServiceConfig.getAudience());
|
||||
}
|
||||
|
||||
return authRequestBuilder.build().toUriString();
|
||||
return builder.build()
|
||||
.toUriString();
|
||||
}
|
||||
|
||||
private Set<String> getScopes(ClientRegistration clientRegistration)
|
||||
private Set<String> getConfiguredScopes(ClientRegistration clientRegistration)
|
||||
{
|
||||
return Optional.ofNullable(clientRegistration.getProviderDetails())
|
||||
.map(ProviderDetails::getConfigurationMetadata)
|
||||
@@ -223,100 +167,149 @@ public class IdentityServiceAdminConsoleAuthenticator implements AdminConsoleAut
|
||||
|
||||
private Set<String> getSupportedScopes(Scope scopes)
|
||||
{
|
||||
Set<String> configuredScopes = getConfiguredScopes();
|
||||
return scopes.stream()
|
||||
.filter(this::hasAdminConsoleScope)
|
||||
.map(Identifier::getValue)
|
||||
.filter(configuredScopes::contains)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private boolean hasAdminConsoleScope(Scope.Value scope)
|
||||
{
|
||||
return identityServiceConfig.getAdminConsoleScopes().contains(scope.getValue());
|
||||
}
|
||||
|
||||
private String getRedirectUri(String requestURL)
|
||||
protected String buildRedirectUri(String requestURL, String overridePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
URI originalUri = new URI(requestURL);
|
||||
URI redirectUri = new URI(originalUri.getScheme(), originalUri.getAuthority(), identityServiceConfig.getAdminConsoleRedirectPath(), originalUri.getQuery(), originalUri.getFragment());
|
||||
String path = overridePath != null ? overridePath : originalUri.getPath();
|
||||
|
||||
URI redirectUri = new URI(
|
||||
originalUri.getScheme(),
|
||||
originalUri.getAuthority(),
|
||||
path,
|
||||
originalUri.getQuery(),
|
||||
originalUri.getFragment());
|
||||
|
||||
return redirectUri.toASCIIString();
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
LOGGER.error("Error while trying to get the redirect URI and respond with the authentication challenge: {}", e.getMessage(), e);
|
||||
LOGGER.error("Redirect URI construction failed: {}", e.getMessage(), e);
|
||||
throw new AuthenticationException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetCookies(HttpServletResponse response)
|
||||
public void challenge(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
response.sendRedirect(buildAuthRequestUrl(request));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new AuthenticationException("Auth redirect failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String retrieveTokenUsingAuthCode(HttpServletRequest request, HttpServletResponse response, String code)
|
||||
{
|
||||
try
|
||||
{
|
||||
AccessTokenAuthorization accessTokenAuthorization = identityServiceFacade.authorize(authorizationCode(code, getRedirectUri(request.getRequestURL()
|
||||
.toString())));
|
||||
addCookies(response, accessTokenAuthorization);
|
||||
return accessTokenAuthorization.getAccessToken()
|
||||
.getTokenValue();
|
||||
}
|
||||
catch (AuthorizationException exception)
|
||||
{
|
||||
LOGGER.warn("Error while trying to retrieve token using Authorization Code: {}", exception.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected String refreshTokenIfNeeded(HttpServletRequest request, HttpServletResponse response, String bearerToken)
|
||||
{
|
||||
String refreshToken = cookiesService.getCookie(ALFRESCO_REFRESH_TOKEN, request);
|
||||
String authTokenExpiration = cookiesService.getCookie(ALFRESCO_TOKEN_EXPIRATION, request);
|
||||
|
||||
try
|
||||
{
|
||||
if (isAuthTokenExpired(authTokenExpiration))
|
||||
{
|
||||
bearerToken = refreshAuthToken(refreshToken, response);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Token refresh failed: {}", e.getMessage());
|
||||
}
|
||||
bearerToken = null;
|
||||
resetCookies(response);
|
||||
}
|
||||
|
||||
return bearerToken;
|
||||
}
|
||||
|
||||
private static boolean isAuthTokenExpired(String authTokenExpiration)
|
||||
{
|
||||
return authTokenExpiration == null || Instant.now()
|
||||
.compareTo(Instant.ofEpochMilli(Long.parseLong(authTokenExpiration))) >= 0;
|
||||
}
|
||||
|
||||
private String refreshAuthToken(String refreshToken, HttpServletResponse response)
|
||||
{
|
||||
AccessTokenAuthorization accessTokenAuthorization = identityServiceFacade.authorize(AuthorizationGrant.refreshToken(refreshToken));
|
||||
if (accessTokenAuthorization == null || accessTokenAuthorization.getAccessToken() == null)
|
||||
{
|
||||
throw new AuthenticationException("Refresh token response is invalid.");
|
||||
}
|
||||
addCookies(response, accessTokenAuthorization);
|
||||
return accessTokenAuthorization.getAccessToken()
|
||||
.getTokenValue();
|
||||
|
||||
}
|
||||
|
||||
protected void addCookies(HttpServletResponse response, AccessTokenAuthorization accessTokenAuthorization)
|
||||
{
|
||||
cookiesService.addCookie(ALFRESCO_ACCESS_TOKEN, accessTokenAuthorization.getAccessToken()
|
||||
.getTokenValue(), response);
|
||||
cookiesService.addCookie(ALFRESCO_TOKEN_EXPIRATION, String.valueOf(accessTokenAuthorization.getAccessToken()
|
||||
.getExpiresAt()
|
||||
.toEpochMilli()), response);
|
||||
cookiesService.addCookie(ALFRESCO_REFRESH_TOKEN, accessTokenAuthorization.getRefreshTokenValue(), response);
|
||||
}
|
||||
|
||||
protected void resetCookies(HttpServletResponse response)
|
||||
{
|
||||
cookiesService.resetCookie(ALFRESCO_TOKEN_EXPIRATION, response);
|
||||
cookiesService.resetCookie(ALFRESCO_ACCESS_TOKEN, response);
|
||||
cookiesService.resetCookie(ALFRESCO_REFRESH_TOKEN, response);
|
||||
}
|
||||
|
||||
private String refreshAuthToken(String refreshToken, HttpServletResponse response)
|
||||
protected HttpServletRequest newRequestWrapper(Map<String, String> headers, HttpServletRequest request)
|
||||
{
|
||||
AccessTokenAuthorization accessTokenAuthorization = doRefreshAuthToken(refreshToken);
|
||||
addCookies(response, accessTokenAuthorization);
|
||||
return accessTokenAuthorization.getAccessToken().getTokenValue();
|
||||
return new AdditionalHeadersHttpServletRequestWrapper(headers, request);
|
||||
}
|
||||
|
||||
private AccessTokenAuthorization doRefreshAuthToken(String refreshToken)
|
||||
// Setters
|
||||
public void setIdentityServiceConfig(IdentityServiceConfig config)
|
||||
{
|
||||
AccessTokenAuthorization accessTokenAuthorization = identityServiceFacade.authorize(
|
||||
AuthorizationGrant.refreshToken(refreshToken));
|
||||
if (accessTokenAuthorization == null || accessTokenAuthorization.getAccessToken() == null)
|
||||
{
|
||||
throw new AuthenticationException("AccessTokenResponse is null or empty");
|
||||
}
|
||||
return accessTokenAuthorization;
|
||||
this.identityServiceConfig = config;
|
||||
}
|
||||
|
||||
private static boolean isAuthTokenExpired(String authTokenExpiration)
|
||||
public void setIdentityServiceFacade(IdentityServiceFacade facade)
|
||||
{
|
||||
return Instant.now().compareTo(Instant.ofEpochMilli(Long.parseLong(authTokenExpiration))) >= 0;
|
||||
this.identityServiceFacade = facade;
|
||||
}
|
||||
|
||||
private HttpServletRequest decorateBearerHeader(String authToken, HttpServletRequest servletRequest)
|
||||
public void setCookiesService(AdminAuthenticationCookiesService service)
|
||||
{
|
||||
Map<String, String> additionalHeaders = new HashMap<>();
|
||||
additionalHeaders.put("Authorization", "Bearer " + authToken);
|
||||
return new AdminConsoleHttpServletRequestWrapper(additionalHeaders, servletRequest);
|
||||
this.cookiesService = service;
|
||||
}
|
||||
|
||||
public void setIdentityServiceFacade(
|
||||
IdentityServiceFacade identityServiceFacade)
|
||||
public void setRemoteUserMapper(RemoteUserMapper mapper)
|
||||
{
|
||||
this.identityServiceFacade = identityServiceFacade;
|
||||
}
|
||||
|
||||
public void setRemoteUserMapper(RemoteUserMapper remoteUserMapper)
|
||||
{
|
||||
this.remoteUserMapper = remoteUserMapper;
|
||||
}
|
||||
|
||||
public void setCookiesService(
|
||||
AdminConsoleAuthenticationCookiesService cookiesService)
|
||||
{
|
||||
this.cookiesService = cookiesService;
|
||||
}
|
||||
|
||||
public void setIdentityServiceConfig(
|
||||
IdentityServiceConfig identityServiceConfig)
|
||||
{
|
||||
this.identityServiceConfig = identityServiceConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return this.isEnabled;
|
||||
}
|
||||
|
||||
public void setActive(boolean isEnabled)
|
||||
{
|
||||
this.isEnabled = isEnabled;
|
||||
this.remoteUserMapper = mapper;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.identityservice.admin;
|
||||
package org.alfresco.repo.security.authentication.identityservice.authentication;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.enumeration;
|
||||
@@ -37,20 +37,12 @@ import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
|
||||
public class AdminConsoleHttpServletRequestWrapper extends HttpServletRequestWrapper
|
||||
public class AdditionalHeadersHttpServletRequestWrapper extends HttpServletRequestWrapper
|
||||
{
|
||||
private final Map<String, String> additionalHeaders;
|
||||
private final HttpServletRequest wrappedRequest;
|
||||
|
||||
/**
|
||||
* Constructs a request object wrapping the given request.
|
||||
*
|
||||
* @param request
|
||||
* the request to wrap
|
||||
* @throws IllegalArgumentException
|
||||
* if the request is null
|
||||
*/
|
||||
public AdminConsoleHttpServletRequestWrapper(Map<String, String> additionalHeaders, HttpServletRequest request)
|
||||
public AdditionalHeadersHttpServletRequestWrapper(Map<String, String> additionalHeaders, HttpServletRequest request)
|
||||
{
|
||||
super(request);
|
||||
PropertyCheck.mandatory(this, "additionalHeaders", additionalHeaders);
|
||||
@@ -23,7 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.identityservice.admin;
|
||||
package org.alfresco.repo.security.authentication.identityservice.authentication;
|
||||
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -34,12 +34,12 @@ import org.alfresco.repo.admin.SysAdminParams;
|
||||
/**
|
||||
* Service to handle Admin Console authentication-related cookies.
|
||||
*/
|
||||
public class AdminConsoleAuthenticationCookiesService
|
||||
public class AdminAuthenticationCookiesService
|
||||
{
|
||||
private final SysAdminParams sysAdminParams;
|
||||
private final int cookieLifetime;
|
||||
|
||||
public AdminConsoleAuthenticationCookiesService(SysAdminParams sysAdminParams, int cookieLifetime)
|
||||
public AdminAuthenticationCookiesService(SysAdminParams sysAdminParams, int cookieLifetime)
|
||||
{
|
||||
this.sysAdminParams = sysAdminParams;
|
||||
this.cookieLifetime = cookieLifetime;
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.authentication.identityservice.authentication.admin;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
import org.alfresco.repo.security.authentication.external.ExternalUserAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AbstractIdentityServiceAuthenticator;
|
||||
|
||||
/**
|
||||
* An {@link ExternalUserAuthenticator} implementation to extract an externally authenticated user ID or to initiate the OIDC authorization code flow.
|
||||
*/
|
||||
public class IdentityServiceAdminConsoleAuthenticator extends AbstractIdentityServiceAuthenticator
|
||||
implements ExternalUserAuthenticator, ActivateableBean
|
||||
{
|
||||
private boolean isEnabled;
|
||||
|
||||
@Override
|
||||
protected Set<String> getConfiguredScopes()
|
||||
{
|
||||
return identityServiceConfig.getAdminConsoleScopes();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConfiguredRedirectPath()
|
||||
{
|
||||
return identityServiceConfig.getAdminConsoleRedirectPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public void setActive(boolean isEnabled)
|
||||
{
|
||||
this.isEnabled = isEnabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.authentication.identityservice.authentication.webscripts;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
import org.alfresco.repo.security.authentication.external.ExternalUserAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AbstractIdentityServiceAuthenticator;
|
||||
|
||||
/**
|
||||
* An {@link ExternalUserAuthenticator} implementation to extract an externally authenticated user ID or to initiate the OIDC authorization code flow.
|
||||
*/
|
||||
public class IdentityServiceWebScriptsHomeAuthenticator extends AbstractIdentityServiceAuthenticator
|
||||
implements ExternalUserAuthenticator, ActivateableBean
|
||||
{
|
||||
private boolean isEnabled;
|
||||
|
||||
@Override
|
||||
protected String getConfiguredRedirectPath()
|
||||
{
|
||||
return identityServiceConfig.getWebScriptsHomeRedirectPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> getConfiguredScopes()
|
||||
{
|
||||
return identityServiceConfig.getWebScriptsHomeScopes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return this.isEnabled;
|
||||
}
|
||||
|
||||
public void setActive(boolean isEnabled)
|
||||
{
|
||||
this.isEnabled = isEnabled;
|
||||
}
|
||||
}
|
||||
@@ -248,4 +248,9 @@ public interface AuthorityDAO
|
||||
* Remove an authority from zones.
|
||||
*/
|
||||
public void removeAuthorityFromZones(String authorityName, Set<String> zones);
|
||||
|
||||
/**
|
||||
* @return Returns the authority container, <b>which must exist</b>
|
||||
*/
|
||||
NodeRef getAuthorityContainer();
|
||||
}
|
||||
|
||||
@@ -1360,7 +1360,8 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
|
||||
/**
|
||||
* @return Returns the authority container, <b>which must exist</b>
|
||||
*/
|
||||
private NodeRef getAuthorityContainer()
|
||||
@Override
|
||||
public NodeRef getAuthorityContainer()
|
||||
{
|
||||
return getSystemContainer(qnameAssocAuthorities);
|
||||
}
|
||||
|
||||
@@ -411,6 +411,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
|
||||
Date groupLastModified = groupLastModifiedMillis == -1 ? null : new Date(groupLastModifiedMillis);
|
||||
Date personLastModified = personLastModifiedMillis == -1 ? null : new Date(personLastModifiedMillis);
|
||||
|
||||
plugin.initSync(groupLastModified, syncDelete);
|
||||
ret.setGroups(plugin.getGroupNames());
|
||||
|
||||
ret.setUsers(plugin.getPersonNames());
|
||||
@@ -918,7 +919,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
|
||||
: getMostRecentUpdateTime(
|
||||
ChainingUserRegistrySynchronizer.GROUP_LAST_MODIFIED_ATTRIBUTE, zoneId, splitTxns);
|
||||
Date lastModified = lastModifiedMillis == -1 ? null : new Date(lastModifiedMillis);
|
||||
|
||||
userRegistry.initSync(lastModified, syncDelete);
|
||||
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled())
|
||||
{
|
||||
if (lastModified == null)
|
||||
@@ -945,6 +946,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
|
||||
this.loggingInterval);
|
||||
class Analyzer extends BaseBatchProcessWorker<NodeDescription>
|
||||
{
|
||||
private final Map<String, NodeDescription> nodeDescriptions = new HashMap<>();
|
||||
private final Map<String, String> groupsToCreate = new TreeMap<String, String>();
|
||||
private final Map<String, Set<String>> personParentAssocsToCreate = newPersonMap();
|
||||
private final Map<String, Set<String>> personParentAssocsToDelete = newPersonMap();
|
||||
@@ -1103,6 +1105,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
|
||||
{
|
||||
PropertyMap groupProperties = group.getProperties();
|
||||
String groupName = (String) groupProperties.get(ContentModel.PROP_AUTHORITY_NAME);
|
||||
nodeDescriptions.put(groupName, group);
|
||||
String groupDisplayName = (String) groupProperties.get(ContentModel.PROP_AUTHORITY_DISPLAY_NAME);
|
||||
if (groupDisplayName == null)
|
||||
{
|
||||
@@ -1565,9 +1568,11 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean
|
||||
+ groupShortName + "'");
|
||||
}
|
||||
// create the group
|
||||
Map<QName, Serializable> groupProperties = Optional.ofNullable(Analyzer.this.nodeDescriptions.get(child))
|
||||
.map(NodeDescription::getProperties)
|
||||
.orElse(new PropertyMap());
|
||||
ChainingUserRegistrySynchronizer.this.authorityService.createAuthority(
|
||||
AuthorityType.getAuthorityType(child), groupShortName, groupDisplayName,
|
||||
zoneSet);
|
||||
AuthorityType.getAuthorityType(child), groupShortName, groupDisplayName, zoneSet, groupProperties);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,21 +4,21 @@
|
||||
* %%
|
||||
* 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
|
||||
* 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%
|
||||
@@ -33,14 +33,14 @@ import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* A <code>UserRegistry</code> is an encapsulation of an external registry from which user and group information can be queried (typically an LDAP directory). Implementations may optional support the ability to query only those users and groups modified since a certain time.
|
||||
*
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
public interface UserRegistry
|
||||
{
|
||||
/**
|
||||
* Gets descriptions of all the persons (users) in the user registry or all those changed since a certain date.
|
||||
*
|
||||
*
|
||||
* @param modifiedSince
|
||||
* if non-null, then only descriptions of users modified since this date should be returned; if <code>null</code> then descriptions of all users should be returned.
|
||||
* @return a {@link Collection} of {@link NodeDescription}s of all the persons (users) in the user registry or all those changed since a certain date. The description properties should correspond to those of an Alfresco person node.
|
||||
@@ -49,7 +49,7 @@ public interface UserRegistry
|
||||
|
||||
/**
|
||||
* Gets descriptions of all the groups in the user registry or all those changed since a certain date.
|
||||
*
|
||||
*
|
||||
* @param modifiedSince
|
||||
* if non-null, then only descriptions of groups modified since this date should be returned; if <code>null</code> then descriptions of all groups should be returned.
|
||||
* @return a {@link Collection} of {@link NodeDescription}s of all the groups in the user registry or all those changed since a certain date. The description properties should correspond to those of an Alfresco authority node.
|
||||
@@ -58,22 +58,35 @@ public interface UserRegistry
|
||||
|
||||
/**
|
||||
* Gets the names of all persons in the registry. Used to detect local persons to be deleted. Note that the treatment of these names will depend on Alfresco's username case-sensitivity setting.
|
||||
*
|
||||
*
|
||||
* @return the person names
|
||||
*/
|
||||
public Collection<String> getPersonNames();
|
||||
|
||||
/**
|
||||
* Gets the names of all groups in the registry. Used to detect local groups to be deleted.
|
||||
*
|
||||
*
|
||||
* @return the person names
|
||||
*/
|
||||
public Collection<String> getGroupNames();
|
||||
|
||||
/**
|
||||
* Gets the set of property names that are auto-mapped by this user registry. These should remain read-only for this registry's users in the UI.
|
||||
*
|
||||
*
|
||||
* @return the person mapped properties
|
||||
*/
|
||||
public Set<QName> getPersonMappedProperties();
|
||||
|
||||
/**
|
||||
* Notifies the user registry that the sync process is about to start.
|
||||
*
|
||||
* @param modifiedSince
|
||||
* if non-null, then only descriptions of groups and users modified since this date should be returned; if <code>null</code> then descriptions of all groups and users should be returned.
|
||||
* @param syncDelete
|
||||
* if <code>true</code> then registry will be queried for all users and groups to calculate deleted entities
|
||||
*/
|
||||
default void initSync(Date modifiedSince, boolean syncDelete)
|
||||
{
|
||||
// default implementation does nothing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,7 +914,7 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic
|
||||
String[] tokenizedFilter = SearchLanguageConversion.tokenizeString(escNameFilter);
|
||||
|
||||
// cm:name
|
||||
query.append(" cm:name:\" ");
|
||||
query.append(" cm:name:\"");
|
||||
for (int i = 0; i < tokenizedFilter.length; i++)
|
||||
{
|
||||
if (i != 0) // Not first element
|
||||
|
||||
@@ -43,6 +43,7 @@ public class FileExistsException extends AlfrescoRuntimeException
|
||||
|
||||
private NodeRef parentNodeRef;
|
||||
private String name;
|
||||
private String type;
|
||||
|
||||
public FileExistsException(NodeRef parentNodeRef, String name)
|
||||
{
|
||||
@@ -51,6 +52,14 @@ public class FileExistsException extends AlfrescoRuntimeException
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public FileExistsException(NodeRef parentNodeRef, String name, String type)
|
||||
{
|
||||
super(MESSAGE_ID, new Object[]{name});
|
||||
this.parentNodeRef = parentNodeRef;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public NodeRef getParentNodeRef()
|
||||
{
|
||||
return parentNodeRef;
|
||||
@@ -60,4 +69,9 @@ public class FileExistsException extends AlfrescoRuntimeException
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* #%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.model;
|
||||
|
||||
import org.alfresco.api.AlfrescoPublicApi;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Common exception thrown when an operation fails because of a name clash of folder.
|
||||
*
|
||||
*/
|
||||
@AlfrescoPublicApi
|
||||
public class FolderExistsException extends AlfrescoRuntimeException
|
||||
{
|
||||
private static final String MESSAGE_ID = "file_folder_service.file_exists_message";
|
||||
|
||||
private static final long serialVersionUID = -4133713912784624118L;
|
||||
|
||||
private NodeRef parentNodeRef;
|
||||
private String name;
|
||||
|
||||
public FolderExistsException(NodeRef parentNodeRef, String name)
|
||||
{
|
||||
super(MESSAGE_ID, new Object[]{name});
|
||||
this.parentNodeRef = parentNodeRef;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NodeRef getParentNodeRef()
|
||||
{
|
||||
return parentNodeRef;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@
|
||||
</property>
|
||||
<property name="interfaces">
|
||||
<list>
|
||||
<value>org.alfresco.repo.security.authentication.external.AdminConsoleAuthenticator</value>
|
||||
<value>org.alfresco.repo.security.authentication.external.ExternalUserAuthenticator</value>
|
||||
<value>org.alfresco.repo.management.subsystems.ActivateableBean</value>
|
||||
</list>
|
||||
</property>
|
||||
@@ -144,6 +144,22 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="WebScriptsHomeAuthenticator"
|
||||
class="org.alfresco.repo.management.subsystems.ChainingSubsystemProxyFactory">
|
||||
<property name="applicationContextManager">
|
||||
<ref bean="Authentication" />
|
||||
</property>
|
||||
<property name="interfaces">
|
||||
<list>
|
||||
<value>org.alfresco.repo.security.authentication.external.ExternalUserAuthenticator</value>
|
||||
<value>org.alfresco.repo.management.subsystems.ActivateableBean</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="sourceBeanName">
|
||||
<value>webScriptsHomeAuthenticator</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Passwords are encoded using MD4 -->
|
||||
<!-- This is not ideal and only done to be compatible with NTLM -->
|
||||
<!-- authentication against the default authentication mechanism. -->
|
||||
|
||||
@@ -141,9 +141,10 @@
|
||||
<property name="childByNameCache" ref="node.childByNameCache"/>
|
||||
<property name="cachingThreshold" value="${nodes.bulkLoad.cachingThreshold}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="nodeDAO.org.alfresco.repo.domain.dialect.Dialect" class="org.alfresco.repo.domain.node.ibatis.NodeDAOImpl" parent="nodeDAObase" />
|
||||
<bean id="nodeDAO.org.alfresco.repo.domain.dialect.MySQLInnoDBDialect" class="org.alfresco.repo.domain.node.ibatis.NodeDAOImpl$MySQL" parent="nodeDAO.org.alfresco.repo.domain.dialect.Dialect" />
|
||||
<bean id="nodeDAO.org.alfresco.repo.domain.dialect.AlfrescoSQLServerDialect" class="org.alfresco.repo.domain.node.ibatis.NodeDAOImpl$MSSQL" parent="nodeDAO.org.alfresco.repo.domain.dialect.Dialect" />
|
||||
<bean id="nodeDAO.org.alfresco.repo.domain.dialect.SQLServerDialect" class="org.alfresco.repo.domain.node.ibatis.NodeDAOImpl$MSSQL" parent="nodeDAO.org.alfresco.repo.domain.dialect.Dialect" />
|
||||
|
||||
<!-- WARNING: Experimental/unsupported - see MySQLClusterNDBDialect ! -->
|
||||
<bean id="nodeDAO.org.alfresco.repo.domain.dialect.AlfrescoMySQLClusterNDBDialect" class="org.alfresco.repo.domain.node.ibatis.NodeDAOImpl$MySQLClusterNDB" parent="nodeDAO.org.alfresco.repo.domain.dialect.Dialect" />
|
||||
|
||||
@@ -563,6 +563,7 @@ authentication.ticket.validDuration=PT1H
|
||||
authentication.ticket.useSingleTicketPerUser=true
|
||||
|
||||
authentication.alwaysAllowBasicAuthForAdminConsole.enabled=true
|
||||
authentication.alwaysAllowBasicAuthForWebScriptsHome.enabled=true
|
||||
authentication.getRemoteUserTimeoutMilliseconds=10000
|
||||
|
||||
# FTP access
|
||||
|
||||
@@ -104,4 +104,7 @@
|
||||
<ref bean="transactionService" />
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
|
||||
<bean id="webScriptsHomeAuthenticator" class="org.alfresco.repo.security.authentication.external.DefaultWebScriptsHomeAuthenticator" />
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -170,6 +170,9 @@
|
||||
<property name="adminConsoleScopes">
|
||||
<value>${identity-service.admin-console.scopes:openid,profile,email,offline_access}</value>
|
||||
</property>
|
||||
<property name="webScriptsHomeScopes">
|
||||
<value>${identity-service.webscripts-home.scopes:openid,profile,email,offline_access}</value>
|
||||
</property>
|
||||
<property name="passwordGrantScopes">
|
||||
<value>${identity-service.password-grant.scopes:openid,profile,email}</value>
|
||||
</property>
|
||||
@@ -179,6 +182,9 @@
|
||||
<property name="jwtClockSkewMs">
|
||||
<value>${identity-service.jwt-clock-skew-ms:0}</value>
|
||||
</property>
|
||||
<property name="webScriptsHomeRedirectPath">
|
||||
<value>${identity-service.webscripts-home.redirect-path}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Enable control over mapping between request and user ID -->
|
||||
@@ -197,12 +203,12 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="adminConsoleAuthenticationCookiesService" class="org.alfresco.repo.security.authentication.identityservice.admin.AdminConsoleAuthenticationCookiesService">
|
||||
<constructor-arg ref="sysAdminParams" />
|
||||
<constructor-arg value="${admin.console.cookie.lifetime:86400}" />
|
||||
</bean>
|
||||
<bean id="adminAuthenticationCookiesService" class="org.alfresco.repo.security.authentication.identityservice.authentication.AdminAuthenticationCookiesService">
|
||||
<constructor-arg ref="sysAdminParams" />
|
||||
<constructor-arg value="${admin.console.cookie.lifetime:86400}" />
|
||||
</bean>
|
||||
|
||||
<bean id="adminConsoleAuthenticator" class="org.alfresco.repo.security.authentication.identityservice.admin.IdentityServiceAdminConsoleAuthenticator">
|
||||
<bean id="adminConsoleAuthenticator" class="org.alfresco.repo.security.authentication.identityservice.authentication.admin.IdentityServiceAdminConsoleAuthenticator">
|
||||
<property name="active">
|
||||
<value>${identity-service.authentication.enabled}</value>
|
||||
</property>
|
||||
@@ -210,7 +216,7 @@
|
||||
<ref bean="identityServiceFacade"/>
|
||||
</property>
|
||||
<property name="cookiesService">
|
||||
<ref bean="adminConsoleAuthenticationCookiesService" />
|
||||
<ref bean="adminAuthenticationCookiesService" />
|
||||
</property>
|
||||
<property name="remoteUserMapper">
|
||||
<ref bean="remoteUserMapper" />
|
||||
@@ -220,6 +226,24 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="webScriptsHomeAuthenticator" class="org.alfresco.repo.security.authentication.identityservice.authentication.webscripts.IdentityServiceWebScriptsHomeAuthenticator">
|
||||
<property name="active">
|
||||
<value>${identity-service.authentication.enabled}</value>
|
||||
</property>
|
||||
<property name="identityServiceFacade">
|
||||
<ref bean="identityServiceFacade"/>
|
||||
</property>
|
||||
<property name="cookiesService">
|
||||
<ref bean="adminAuthenticationCookiesService" />
|
||||
</property>
|
||||
<property name="remoteUserMapper">
|
||||
<ref bean="remoteUserMapper" />
|
||||
</property>
|
||||
<property name="identityServiceConfig">
|
||||
<ref bean="identityServiceConfig" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="jitProvisioningHandler" class="org.alfresco.repo.security.authentication.identityservice.IdentityServiceJITProvisioningHandler">
|
||||
<constructor-arg ref="PersonService"/>
|
||||
<constructor-arg ref="identityServiceFacade"/>
|
||||
|
||||
@@ -12,11 +12,13 @@ identity-service.resource=alfresco
|
||||
identity-service.credentials.secret=
|
||||
identity-service.public-client=true
|
||||
identity-service.admin-console.redirect-path=/alfresco/s/admin/admin-communitysummary
|
||||
identity-service.webscripts-home.redirect-path=/alfresco/s/index
|
||||
identity-service.signature-algorithms=RS256,PS256
|
||||
identity-service.first-name-attribute=given_name
|
||||
identity-service.last-name-attribute=family_name
|
||||
identity-service.email-attribute=email
|
||||
identity-service.admin-console.scopes=openid,profile,email,offline_access
|
||||
identity-service.webscripts-home.scopes=openid,profile,email,offline_access
|
||||
identity-service.password-grant.scopes=openid,profile,email
|
||||
identity-service.issuer-attribute=issuer
|
||||
identity-service.jwt-clock-skew-ms=0
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -54,6 +54,7 @@ import org.alfresco.util.testing.category.NonBuildTests;
|
||||
|
||||
// From AppContext05TestSuite
|
||||
org.alfresco.repo.domain.node.NodeDAOTest.class,
|
||||
org.alfresco.repo.domain.subscriptions.SubscriptionDAOTest.class,
|
||||
org.alfresco.repo.security.permissions.impl.AclDaoComponentTest.class,
|
||||
org.alfresco.repo.domain.contentdata.ContentDataDAOTest.class,
|
||||
org.alfresco.repo.domain.encoding.EncodingDAOTest.class,
|
||||
|
||||
@@ -34,11 +34,12 @@ import org.alfresco.repo.security.authentication.identityservice.IdentityService
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceJITProvisioningHandlerUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.LazyInstantiatingIdentityServiceFacadeUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.SpringBasedIdentityServiceFacadeUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.admin.AdminConsoleAuthenticationCookiesServiceUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.admin.AdminConsoleHttpServletRequestWrapperUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.admin.IdentityServiceAdminConsoleAuthenticatorUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AdditionalHeadersHttpServletRequestWrapperUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AdminAuthenticationCookiesServiceUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.admin.IdentityServiceAdminConsoleAuthenticatorUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.user.AccessTokenToDecodedTokenUserMapperUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.user.TokenUserToOIDCUserMapperUnitTest;
|
||||
import org.alfresco.repo.security.authentication.identityservice.webscript.IdentityServiceWebScriptsHomeAuthenticatorUnitTest;
|
||||
import org.alfresco.util.testing.category.DBTests;
|
||||
import org.alfresco.util.testing.category.NonBuildTests;
|
||||
|
||||
@@ -153,9 +154,10 @@ import org.alfresco.util.testing.category.NonBuildTests;
|
||||
IdentityServiceJITProvisioningHandlerUnitTest.class,
|
||||
AccessTokenToDecodedTokenUserMapperUnitTest.class,
|
||||
TokenUserToOIDCUserMapperUnitTest.class,
|
||||
AdminConsoleAuthenticationCookiesServiceUnitTest.class,
|
||||
AdminConsoleHttpServletRequestWrapperUnitTest.class,
|
||||
AdminAuthenticationCookiesServiceUnitTest.class,
|
||||
AdditionalHeadersHttpServletRequestWrapperUnitTest.class,
|
||||
IdentityServiceAdminConsoleAuthenticatorUnitTest.class,
|
||||
IdentityServiceWebScriptsHomeAuthenticatorUnitTest.class,
|
||||
ClientRegistrationProviderUnitTest.class,
|
||||
org.alfresco.repo.security.authentication.CompositePasswordEncoderTest.class,
|
||||
org.alfresco.repo.security.authentication.PasswordHashingTest.class,
|
||||
|
||||
@@ -25,10 +25,7 @@
|
||||
*/
|
||||
package org.alfresco.repo.action.executer;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -48,6 +45,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.model.FolderExistsException;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -340,6 +338,49 @@ public class ImporterActionExecuterTest
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateUnzipping() throws IOException
|
||||
{
|
||||
final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper();
|
||||
|
||||
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
|
||||
{
|
||||
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
|
||||
|
||||
// create test data
|
||||
NodeRef zipFileNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTENT).getChildRef();
|
||||
NodeRef targetFolderNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_FOLDER).getChildRef();
|
||||
|
||||
putContent(zipFileNodeRef, "import-archive-test/accentCharTestZip.zip");
|
||||
|
||||
Action action = createAction(zipFileNodeRef, "ImporterActionExecuterTestActionDefinition", targetFolderNodeRef);
|
||||
|
||||
try
|
||||
{
|
||||
importerActionExecuter.setUncompressedBytesLimit("100000");
|
||||
importerActionExecuter.execute(action, zipFileNodeRef);
|
||||
// unzip again to duplicate node
|
||||
importerActionExecuter.execute(action, zipFileNodeRef);
|
||||
}
|
||||
catch (FolderExistsException e)
|
||||
{
|
||||
assertTrue(e.getMessage().contains("File or folder accentCharTestZip already exists"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// clean test data
|
||||
nodeService.deleteNode(targetFolderNodeRef);
|
||||
nodeService.deleteNode(zipFileNodeRef);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void putContent(NodeRef zipFileNodeRef, String resource)
|
||||
{
|
||||
URL url = AbstractContentTransformerTest.class.getClassLoader().getResource(resource);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -43,9 +43,9 @@ import org.alfresco.service.cmr.subscriptions.SubscriptionItemTypeEnum;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.test_category.OwnJVMTestsCategory;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.testing.category.NeverRunsTests;
|
||||
import org.alfresco.util.testing.category.DBTests;
|
||||
|
||||
@Category({OwnJVMTestsCategory.class, NeverRunsTests.class})
|
||||
@Category({OwnJVMTestsCategory.class, DBTests.class})
|
||||
public class SubscriptionDAOTest extends TestCase
|
||||
{
|
||||
private ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.identityservice.admin;
|
||||
package org.alfresco.repo.security.authentication.identityservice.authentication;
|
||||
|
||||
import static java.util.Collections.enumeration;
|
||||
import static java.util.Collections.list;
|
||||
@@ -49,19 +49,18 @@ import org.mockito.Mock;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
@SuppressWarnings("PMD.UseDiamondOperator")
|
||||
public class AdminConsoleHttpServletRequestWrapperUnitTest
|
||||
public class AdditionalHeadersHttpServletRequestWrapperUnitTest
|
||||
{
|
||||
|
||||
private static final String DEFAULT_HEADER = "default_header";
|
||||
private static final String DEFAULT_HEADER_VALUE = "default_value";
|
||||
private static final String ADDITIONAL_HEADER = "additional_header";
|
||||
private static final String ADDITIONAL_HEADER_VALUE = "additional_value";
|
||||
private static final Map<String, String> DEFAULT_HEADERS = new HashMap<String, String>() {
|
||||
private static final Map<String, String> DEFAULT_HEADERS = new HashMap<>() {
|
||||
{
|
||||
put(DEFAULT_HEADER, DEFAULT_HEADER_VALUE);
|
||||
}
|
||||
};
|
||||
private static final Map<String, String> ADDITIONAL_HEADERS = new HashMap<String, String>() {
|
||||
private static final Map<String, String> ADDITIONAL_HEADERS = new HashMap<>() {
|
||||
{
|
||||
put(ADDITIONAL_HEADER, ADDITIONAL_HEADER_VALUE);
|
||||
}
|
||||
@@ -69,25 +68,25 @@ public class AdminConsoleHttpServletRequestWrapperUnitTest
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest request;
|
||||
private AdminConsoleHttpServletRequestWrapper requestWrapper;
|
||||
private AdditionalHeadersHttpServletRequestWrapper requestWrapper;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
initMocks(this);
|
||||
requestWrapper = new AdminConsoleHttpServletRequestWrapper(ADDITIONAL_HEADERS, request);
|
||||
requestWrapper = new AdditionalHeadersHttpServletRequestWrapper(ADDITIONAL_HEADERS, request);
|
||||
}
|
||||
|
||||
@Test(expected = AlfrescoRuntimeException.class)
|
||||
public void wrapperShouldNotBeInstancedWithoutAdditionalHeaders()
|
||||
{
|
||||
new AdminConsoleHttpServletRequestWrapper(null, request);
|
||||
new AdditionalHeadersHttpServletRequestWrapper(null, request);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void wrapperShouldNotBeInstancedWithoutRequestsToWrap()
|
||||
{
|
||||
new AdminConsoleHttpServletRequestWrapper(new HashMap<>(), null);
|
||||
new AdditionalHeadersHttpServletRequestWrapper(new HashMap<>(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,7 +111,7 @@ public class AdminConsoleHttpServletRequestWrapperUnitTest
|
||||
{
|
||||
when(request.getHeaderNames()).thenReturn(enumeration(DEFAULT_HEADERS.keySet()));
|
||||
|
||||
requestWrapper = new AdminConsoleHttpServletRequestWrapper(new HashMap<>(), request);
|
||||
requestWrapper = new AdditionalHeadersHttpServletRequestWrapper(new HashMap<>(), request);
|
||||
Enumeration<String> headerNames = requestWrapper.getHeaderNames();
|
||||
assertNotNull("headerNames should not be null", headerNames);
|
||||
assertTrue("headerNames should not be empty", headerNames.hasMoreElements());
|
||||
@@ -164,7 +163,7 @@ public class AdminConsoleHttpServletRequestWrapperUnitTest
|
||||
Map<String, String> overrideHeaders = new HashMap<>();
|
||||
overrideHeaders.put(DEFAULT_HEADER, overrideHeaderValue);
|
||||
|
||||
requestWrapper = new AdminConsoleHttpServletRequestWrapper(overrideHeaders, request);
|
||||
requestWrapper = new AdditionalHeadersHttpServletRequestWrapper(overrideHeaders, request);
|
||||
String header = requestWrapper.getHeader(DEFAULT_HEADER);
|
||||
assertEquals("The header should have the overridden value", overrideHeaderValue, header);
|
||||
|
||||
@@ -204,7 +203,7 @@ public class AdminConsoleHttpServletRequestWrapperUnitTest
|
||||
Map<String, String> overrideHeaders = new HashMap<>();
|
||||
overrideHeaders.put(DEFAULT_HEADER, overrideHeaderValue);
|
||||
|
||||
requestWrapper = new AdminConsoleHttpServletRequestWrapper(overrideHeaders, request);
|
||||
requestWrapper = new AdditionalHeadersHttpServletRequestWrapper(overrideHeaders, request);
|
||||
Enumeration<String> headers = requestWrapper.getHeaders(DEFAULT_HEADER);
|
||||
assertNotNull("The headers enumeration should not be null", headers);
|
||||
assertTrue("The headers enumeration should not be empty", headers.hasMoreElements());
|
||||
@@ -23,7 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.identityservice.admin;
|
||||
package org.alfresco.repo.security.authentication.identityservice.authentication;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -46,7 +46,7 @@ import org.mockito.Mock;
|
||||
|
||||
import org.alfresco.repo.admin.SysAdminParams;
|
||||
|
||||
public class AdminConsoleAuthenticationCookiesServiceUnitTest
|
||||
public class AdminAuthenticationCookiesServiceUnitTest
|
||||
{
|
||||
private static final int DEFAULT_COOKIE_LIFETIME = 86400;
|
||||
private static final String COOKIE_NAME = "cookie";
|
||||
@@ -59,13 +59,13 @@ public class AdminConsoleAuthenticationCookiesServiceUnitTest
|
||||
private SysAdminParams sysAdminParams;
|
||||
@Captor
|
||||
private ArgumentCaptor<Cookie> cookieCaptor;
|
||||
private AdminConsoleAuthenticationCookiesService cookiesService;
|
||||
private AdminAuthenticationCookiesService cookiesService;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
initMocks(this);
|
||||
cookiesService = new AdminConsoleAuthenticationCookiesService(sysAdminParams, DEFAULT_COOKIE_LIFETIME);
|
||||
cookiesService = new AdminAuthenticationCookiesService(sysAdminParams, DEFAULT_COOKIE_LIFETIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -138,7 +138,7 @@ public class AdminConsoleAuthenticationCookiesServiceUnitTest
|
||||
public void cookieWithCustomMaxAgeShouldBeAddedToTheResponse()
|
||||
{
|
||||
int customMaxAge = 60;
|
||||
cookiesService = new AdminConsoleAuthenticationCookiesService(sysAdminParams, customMaxAge);
|
||||
cookiesService = new AdminAuthenticationCookiesService(sysAdminParams, customMaxAge);
|
||||
when(sysAdminParams.getAlfrescoProtocol()).thenReturn("https");
|
||||
|
||||
cookiesService.addCookie(COOKIE_NAME, COOKIE_VALUE, response);
|
||||
@@ -23,7 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.identityservice.admin;
|
||||
package org.alfresco.repo.security.authentication.identityservice.authentication.admin;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
@@ -58,11 +58,12 @@ import org.alfresco.repo.security.authentication.identityservice.IdentityService
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AccessTokenAuthorization;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AuthorizationException;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AuthorizationGrant;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AdditionalHeadersHttpServletRequestWrapper;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AdminAuthenticationCookiesService;
|
||||
|
||||
@SuppressWarnings("PMD.AvoidStringBufferField")
|
||||
public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
{
|
||||
|
||||
private static final String ALFRESCO_ACCESS_TOKEN = "ALFRESCO_ACCESS_TOKEN";
|
||||
private static final String ALFRESCO_REFRESH_TOKEN = "ALFRESCO_REFRESH_TOKEN";
|
||||
private static final String ALFRESCO_TOKEN_EXPIRATION = "ALFRESCO_TOKEN_EXPIRATION";
|
||||
@@ -76,7 +77,7 @@ public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
@Mock
|
||||
IdentityServiceConfig identityServiceConfig;
|
||||
@Mock
|
||||
AdminConsoleAuthenticationCookiesService cookiesService;
|
||||
AdminAuthenticationCookiesService cookiesService;
|
||||
@Mock
|
||||
RemoteUserMapper remoteUserMapper;
|
||||
@Mock
|
||||
@@ -84,7 +85,7 @@ public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
@Mock
|
||||
AccessToken accessToken;
|
||||
@Captor
|
||||
ArgumentCaptor<AdminConsoleHttpServletRequestWrapper> requestCaptor;
|
||||
ArgumentCaptor<AdditionalHeadersHttpServletRequestWrapper> requestCaptor;
|
||||
|
||||
IdentityServiceAdminConsoleAuthenticator authenticator;
|
||||
|
||||
@@ -122,7 +123,7 @@ public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
String.valueOf(Instant.now().plusSeconds(60).toEpochMilli()));
|
||||
when(remoteUserMapper.getRemoteUser(requestCaptor.capture())).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getAdminConsoleUser(request, response);
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
assertEquals("Bearer JWT_TOKEN", requestCaptor.getValue().getHeader("Authorization"));
|
||||
assertEquals("admin", username);
|
||||
@@ -143,7 +144,7 @@ public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
when(identityServiceFacade.authorize(any(AuthorizationGrant.class))).thenReturn(accessTokenAuthorization);
|
||||
when(remoteUserMapper.getRemoteUser(requestCaptor.capture())).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getAdminConsoleUser(request, response);
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
verify(cookiesService).addCookie(ALFRESCO_ACCESS_TOKEN, "REFRESHED_JWT_TOKEN", response);
|
||||
verify(cookiesService).addCookie(ALFRESCO_REFRESH_TOKEN, "REFRESH_TOKEN", response);
|
||||
@@ -207,7 +208,7 @@ public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
|
||||
when(identityServiceFacade.authorize(any(AuthorizationGrant.class))).thenThrow(AuthorizationException.class);
|
||||
|
||||
String username = authenticator.getAdminConsoleUser(request, response);
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
verify(cookiesService).resetCookie(ALFRESCO_ACCESS_TOKEN, response);
|
||||
verify(cookiesService).resetCookie(ALFRESCO_REFRESH_TOKEN, response);
|
||||
@@ -228,7 +229,7 @@ public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
.thenReturn(accessTokenAuthorization);
|
||||
when(remoteUserMapper.getRemoteUser(requestCaptor.capture())).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getAdminConsoleUser(request, response);
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
verify(cookiesService).addCookie(ALFRESCO_ACCESS_TOKEN, "JWT_TOKEN", response);
|
||||
verify(cookiesService).addCookie(ALFRESCO_REFRESH_TOKEN, "REFRESH_TOKEN", response);
|
||||
@@ -241,7 +242,7 @@ public class IdentityServiceAdminConsoleAuthenticatorUnitTest
|
||||
{
|
||||
when(remoteUserMapper.getRemoteUser(request)).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getAdminConsoleUser(request, response);
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
assertEquals("admin", username);
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.authentication.identityservice.webscript;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.Scope;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;
|
||||
|
||||
import org.alfresco.repo.security.authentication.external.RemoteUserMapper;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceConfig;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AccessToken;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AccessTokenAuthorization;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AuthorizationException;
|
||||
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.AuthorizationGrant;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AdditionalHeadersHttpServletRequestWrapper;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.AdminAuthenticationCookiesService;
|
||||
import org.alfresco.repo.security.authentication.identityservice.authentication.webscripts.IdentityServiceWebScriptsHomeAuthenticator;
|
||||
|
||||
@SuppressWarnings("PMD.AvoidStringBufferField")
|
||||
public class IdentityServiceWebScriptsHomeAuthenticatorUnitTest
|
||||
{
|
||||
|
||||
private static final String ALFRESCO_ACCESS_TOKEN = "ALFRESCO_ACCESS_TOKEN";
|
||||
private static final String ALFRESCO_REFRESH_TOKEN = "ALFRESCO_REFRESH_TOKEN";
|
||||
private static final String ALFRESCO_TOKEN_EXPIRATION = "ALFRESCO_TOKEN_EXPIRATION";
|
||||
|
||||
@Mock
|
||||
HttpServletRequest request;
|
||||
@Mock
|
||||
HttpServletResponse response;
|
||||
@Mock
|
||||
IdentityServiceFacade identityServiceFacade;
|
||||
@Mock
|
||||
IdentityServiceConfig identityServiceConfig;
|
||||
@Mock
|
||||
AdminAuthenticationCookiesService cookiesService;
|
||||
@Mock
|
||||
RemoteUserMapper remoteUserMapper;
|
||||
@Mock
|
||||
AccessTokenAuthorization accessTokenAuthorization;
|
||||
@Mock
|
||||
AccessToken accessToken;
|
||||
@Captor
|
||||
ArgumentCaptor<AdditionalHeadersHttpServletRequestWrapper> requestCaptor;
|
||||
|
||||
IdentityServiceWebScriptsHomeAuthenticator authenticator;
|
||||
|
||||
StringBuffer webScriptHomeURL = new StringBuffer("http://localhost:8080/alfresco/s/index");
|
||||
|
||||
@Before
|
||||
public void setup()
|
||||
{
|
||||
initMocks(this);
|
||||
ClientRegistration clientRegistration = mock(ClientRegistration.class);
|
||||
ProviderDetails providerDetails = mock(ProviderDetails.class);
|
||||
Scope scope = Scope.parse(Arrays.asList("openid", "profile", "email", "offline_access"));
|
||||
|
||||
when(clientRegistration.getProviderDetails()).thenReturn(providerDetails);
|
||||
when(clientRegistration.getClientId()).thenReturn("alfresco");
|
||||
when(providerDetails.getAuthorizationUri()).thenReturn("http://localhost:8999/auth");
|
||||
when(providerDetails.getConfigurationMetadata()).thenReturn(Map.of("scopes_supported", scope));
|
||||
when(identityServiceFacade.getClientRegistration()).thenReturn(clientRegistration);
|
||||
when(request.getRequestURL()).thenReturn(webScriptHomeURL);
|
||||
when(remoteUserMapper.getRemoteUser(request)).thenReturn(null);
|
||||
|
||||
authenticator = new IdentityServiceWebScriptsHomeAuthenticator();
|
||||
authenticator.setActive(true);
|
||||
authenticator.setIdentityServiceFacade(identityServiceFacade);
|
||||
authenticator.setCookiesService(cookiesService);
|
||||
authenticator.setRemoteUserMapper(remoteUserMapper);
|
||||
authenticator.setIdentityServiceConfig(identityServiceConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCallRemoteMapperIfTokenIsInCookies()
|
||||
{
|
||||
when(cookiesService.getCookie(ALFRESCO_ACCESS_TOKEN, request)).thenReturn("JWT_TOKEN");
|
||||
when(cookiesService.getCookie(ALFRESCO_TOKEN_EXPIRATION, request)).thenReturn(
|
||||
String.valueOf(Instant.now().plusSeconds(60).toEpochMilli()));
|
||||
when(remoteUserMapper.getRemoteUser(requestCaptor.capture())).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
assertEquals("Bearer JWT_TOKEN", requestCaptor.getValue().getHeader("Authorization"));
|
||||
assertEquals("admin", username);
|
||||
assertTrue(authenticator.isActive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRefreshExpiredTokenAndCallRemoteMapper()
|
||||
{
|
||||
when(cookiesService.getCookie(ALFRESCO_ACCESS_TOKEN, request)).thenReturn("EXPIRED_JWT_TOKEN");
|
||||
when(cookiesService.getCookie(ALFRESCO_REFRESH_TOKEN, request)).thenReturn("REFRESH_TOKEN");
|
||||
when(cookiesService.getCookie(ALFRESCO_TOKEN_EXPIRATION, request)).thenReturn(
|
||||
String.valueOf(Instant.now().minusSeconds(60).toEpochMilli()));
|
||||
when(accessToken.getTokenValue()).thenReturn("REFRESHED_JWT_TOKEN");
|
||||
when(accessToken.getExpiresAt()).thenReturn(Instant.now().plusSeconds(60));
|
||||
when(accessTokenAuthorization.getAccessToken()).thenReturn(accessToken);
|
||||
when(accessTokenAuthorization.getRefreshTokenValue()).thenReturn("REFRESH_TOKEN");
|
||||
when(identityServiceFacade.authorize(any(AuthorizationGrant.class))).thenReturn(accessTokenAuthorization);
|
||||
when(remoteUserMapper.getRemoteUser(requestCaptor.capture())).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
verify(cookiesService).addCookie(ALFRESCO_ACCESS_TOKEN, "REFRESHED_JWT_TOKEN", response);
|
||||
verify(cookiesService).addCookie(ALFRESCO_REFRESH_TOKEN, "REFRESH_TOKEN", response);
|
||||
assertEquals("Bearer REFRESHED_JWT_TOKEN", requestCaptor.getValue().getHeader("Authorization"));
|
||||
assertEquals("admin", username);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCallAuthChallengeWebScriptHome() throws IOException
|
||||
{
|
||||
|
||||
String redirectPath = "/alfresco/s/index";
|
||||
when(request.getRequestURL()).thenReturn(webScriptHomeURL);
|
||||
when(identityServiceConfig.getWebScriptsHomeScopes()).thenReturn(Set.of("openid", "email", "profile", "offline_access"));
|
||||
when(identityServiceConfig.getWebScriptsHomeRedirectPath()).thenReturn(redirectPath);
|
||||
ArgumentCaptor<String> authenticationRequest = ArgumentCaptor.forClass(String.class);
|
||||
String expectedUri = "http://localhost:8999/auth?client_id=alfresco&redirect_uri=%s%s&response_type=code&scope="
|
||||
.formatted("http://localhost:8080", redirectPath);
|
||||
|
||||
authenticator.requestAuthentication(request, response);
|
||||
|
||||
verify(response).sendRedirect(authenticationRequest.capture());
|
||||
assertTrue(authenticationRequest.getValue().contains(expectedUri));
|
||||
assertTrue(authenticationRequest.getValue().contains("openid"));
|
||||
assertTrue(authenticationRequest.getValue().contains("profile"));
|
||||
assertTrue(authenticationRequest.getValue().contains("email"));
|
||||
assertTrue(authenticationRequest.getValue().contains("offline_access"));
|
||||
assertTrue(authenticationRequest.getValue().contains("state"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCallAuthChallengeWebScriptHomeWithAudience() throws IOException
|
||||
{
|
||||
String audience = "http://localhost:8082";
|
||||
String redirectPath = "/alfresco/s/index";
|
||||
when(request.getRequestURL()).thenReturn(webScriptHomeURL);
|
||||
when(identityServiceConfig.getAudience()).thenReturn(audience);
|
||||
when(identityServiceConfig.getWebScriptsHomeRedirectPath()).thenReturn(redirectPath);
|
||||
when(identityServiceConfig.getWebScriptsHomeScopes()).thenReturn(Set.of("openid", "email", "profile", "offline_access"));
|
||||
ArgumentCaptor<String> authenticationRequest = ArgumentCaptor.forClass(String.class);
|
||||
String expectedUri = "http://localhost:8999/auth?client_id=alfresco&redirect_uri=%s%s&response_type=code&scope="
|
||||
.formatted("http://localhost:8080", redirectPath);
|
||||
|
||||
authenticator.requestAuthentication(request, response);
|
||||
|
||||
verify(response).sendRedirect(authenticationRequest.capture());
|
||||
assertTrue(authenticationRequest.getValue().contains(expectedUri));
|
||||
assertTrue(authenticationRequest.getValue().contains("openid"));
|
||||
assertTrue(authenticationRequest.getValue().contains("profile"));
|
||||
assertTrue(authenticationRequest.getValue().contains("email"));
|
||||
assertTrue(authenticationRequest.getValue().contains("offline_access"));
|
||||
assertTrue(authenticationRequest.getValue().contains("audience=%s".formatted(audience)));
|
||||
assertTrue(authenticationRequest.getValue().contains("state"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldResetCookiesAndCallAuthChallenge() throws IOException
|
||||
{
|
||||
when(cookiesService.getCookie(ALFRESCO_ACCESS_TOKEN, request)).thenReturn("EXPIRED_JWT_TOKEN");
|
||||
when(cookiesService.getCookie(ALFRESCO_REFRESH_TOKEN, request)).thenReturn("REFRESH_TOKEN");
|
||||
when(cookiesService.getCookie(ALFRESCO_TOKEN_EXPIRATION, request)).thenReturn(
|
||||
String.valueOf(Instant.now().minusSeconds(60).toEpochMilli()));
|
||||
|
||||
when(identityServiceFacade.authorize(any(AuthorizationGrant.class))).thenThrow(AuthorizationException.class);
|
||||
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
verify(cookiesService).resetCookie(ALFRESCO_ACCESS_TOKEN, response);
|
||||
verify(cookiesService).resetCookie(ALFRESCO_REFRESH_TOKEN, response);
|
||||
verify(cookiesService).resetCookie(ALFRESCO_TOKEN_EXPIRATION, response);
|
||||
assertNull(username);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAuthorizeCodeAndSetCookies()
|
||||
{
|
||||
when(request.getParameter("code")).thenReturn("auth_code");
|
||||
when(accessToken.getTokenValue()).thenReturn("JWT_TOKEN");
|
||||
when(accessToken.getExpiresAt()).thenReturn(Instant.now().plusSeconds(60));
|
||||
when(accessTokenAuthorization.getAccessToken()).thenReturn(accessToken);
|
||||
when(accessTokenAuthorization.getRefreshTokenValue()).thenReturn("REFRESH_TOKEN");
|
||||
when(identityServiceFacade.authorize(
|
||||
AuthorizationGrant.authorizationCode("auth_code", webScriptHomeURL.toString())))
|
||||
.thenReturn(accessTokenAuthorization);
|
||||
when(remoteUserMapper.getRemoteUser(requestCaptor.capture())).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
verify(cookiesService).addCookie(ALFRESCO_ACCESS_TOKEN, "JWT_TOKEN", response);
|
||||
verify(cookiesService).addCookie(ALFRESCO_REFRESH_TOKEN, "REFRESH_TOKEN", response);
|
||||
assertEquals("Bearer JWT_TOKEN", requestCaptor.getValue().getHeader("Authorization"));
|
||||
assertEquals("admin", username);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldExtractUsernameFromAuthorizationHeader()
|
||||
{
|
||||
when(remoteUserMapper.getRemoteUser(request)).thenReturn("admin");
|
||||
|
||||
String username = authenticator.getUserId(request, response);
|
||||
|
||||
assertEquals("admin", username);
|
||||
}
|
||||
}
|
||||
@@ -25,26 +25,19 @@
|
||||
*/
|
||||
package org.alfresco.repo.site;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -56,6 +49,8 @@ import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.query.PagingResults;
|
||||
import org.alfresco.repo.admin.SysAdminParams;
|
||||
import org.alfresco.repo.admin.SysAdminParamsImpl;
|
||||
import org.alfresco.repo.cache.MemoryCache;
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.M2Model;
|
||||
import org.alfresco.repo.dictionary.M2Property;
|
||||
@@ -65,6 +60,7 @@ import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
|
||||
import org.alfresco.repo.node.archive.NodeArchiveService;
|
||||
import org.alfresco.repo.node.getchildren.FilterProp;
|
||||
import org.alfresco.repo.node.getchildren.FilterPropString;
|
||||
import org.alfresco.repo.search.EmptyResultSet;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
@@ -78,21 +74,10 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.CopyService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.ScriptLocation;
|
||||
import org.alfresco.service.cmr.repository.ScriptService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AccessPermission;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.AuthorityService;
|
||||
import org.alfresco.service.cmr.security.AuthorityType;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.repository.*;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.security.*;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteMemberInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
@@ -3129,4 +3114,34 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest
|
||||
|
||||
siteService.deleteSite(shortName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindSitesQueryWithReservedCharacter()
|
||||
{
|
||||
// given
|
||||
SiteServiceImpl cut = new SiteServiceImpl();
|
||||
|
||||
ArgumentCaptor<SearchParameters> searchParametersCaptor = ArgumentCaptor.forClass(SearchParameters.class);
|
||||
|
||||
SimpleCache<String, Object> cache = new MemoryCache<>();
|
||||
cache.put("key.sitehome.noderef", new NodeRef("mock", "mock", "mock"));
|
||||
cut.setSingletonCache(cache);
|
||||
|
||||
SearchService searchService = Mockito.mock(SearchService.class);
|
||||
cut.setSearchService(searchService);
|
||||
when(searchService.query(any(SearchParameters.class))).thenReturn(new EmptyResultSet());
|
||||
|
||||
// when
|
||||
cut.findSites("-chu", 5);
|
||||
|
||||
// then
|
||||
verify(searchService).query(searchParametersCaptor.capture());
|
||||
SearchParameters actualSearchParameters = searchParametersCaptor.getValue();
|
||||
assertThat(actualSearchParameters.getQuery())
|
||||
.isEqualTo("+TYPE:\"{http://www.alfresco.org/model/site/1.0}site\""
|
||||
+ " AND ( cm:name:\"\\-chu*\""
|
||||
+ " OR cm:title: (\"\\-chu*\" )"
|
||||
+ " OR cm:description:\"\\-chu\")");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
</onException>
|
||||
<transacted />
|
||||
<loadBalance>
|
||||
<roundRobin/>
|
||||
<roundRobinLoadBalancer/>
|
||||
<to uri="bean:mockExceptionThrowingConsumer"/>
|
||||
<to uri="bean:mockConsumer"/>
|
||||
</loadBalance>
|
||||
|
||||
Reference in New Issue
Block a user