Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally assign IMS group administrators #750

Merged
merged 1 commit into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
ACTOOL_IMS_IT_CLIENTID: ${{ vars.ACTOOL_IMS_IT_CLIENTID }}
ACTOOL_IMS_IT_CLIENTSECRET: ${{ secrets.ACTOOL_IMS_IT_CLIENTSECRET }}
ACTOOL_IMS_IT_PRODUCTPROFILE: ${{ vars.ACTOOL_IMS_IT_PRODUCTPROFILE }}
ACTOOL_IMS_IT_USERID: ${{ vars.ACTOOL_IMS_IT_USERID }}
run: mvn -e -B -V clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=Netcentric_accesscontroltool -Dsonar.organization=netcentric -Dsonar.host.url=https://sonarcloud.io -DnvdApiKeyEnvironmentVariable=NVD_API_KEY -Pdependency-check,coverage-report,integration-tests

- name: Build, Analyse and Deploy with Maven
Expand All @@ -68,4 +69,5 @@ jobs:
ACTOOL_IMS_IT_CLIENTID: ${{ vars.ACTOOL_IMS_IT_CLIENTID }}
ACTOOL_IMS_IT_CLIENTSECRET: ${{ secrets.ACTOOL_IMS_IT_CLIENTSECRET }}
ACTOOL_IMS_IT_PRODUCTPROFILE: ${{ vars.ACTOOL_IMS_IT_PRODUCTPROFILE }}
ACTOOL_IMS_IT_USERID: ${{ vars.ACTOOL_IMS_IT_USERID }}
run: mvn -e -B -V clean deploy org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=Netcentric_accesscontroltool -Dsonar.organization=netcentric -Dsonar.host.url=https://sonarcloud.io -DnvdApiKeyEnvironmentVariable=NVD_API_KEY -Pdependency-check,coverage-report,integration-tests
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -70,8 +71,10 @@
import biz.netcentric.cq.tools.actool.externalusermanagement.ExternalGroupManagement;
import biz.netcentric.cq.tools.actool.ims.IMSUserManagement.Configuration;
import biz.netcentric.cq.tools.actool.ims.request.ActionCommand;
import biz.netcentric.cq.tools.actool.ims.request.AddMembershipStep;
import biz.netcentric.cq.tools.actool.ims.request.AddGroupMembers;
import biz.netcentric.cq.tools.actool.ims.request.AddGroupMembership;
import biz.netcentric.cq.tools.actool.ims.request.CreateGroupStep;
import biz.netcentric.cq.tools.actool.ims.request.UserActionCommand;
import biz.netcentric.cq.tools.actool.ims.request.UserGroupActionCommand;
import biz.netcentric.cq.tools.actool.ims.response.AccessToken;
import biz.netcentric.cq.tools.actool.ims.response.ActionCommandResponse;
Expand Down Expand Up @@ -107,6 +110,8 @@ public class IMSUserManagement implements ExternalGroupManagement {
int socketTimeout() default 10000;
@AttributeDefinition(name = "AEM Product Profiles", description = "The given product profile names are automatically added to each synchronized IMS group. The given product profile names must exist for an AEM product!")
String[] productProfiles() default {};
@AttributeDefinition(name = "Group Administrators", description = "The given users are automatically added to each synchronized IMS group as administrator. The given user ids must already exist!")
String[] groupAdmins() default {};
}

public static final Logger LOG = LoggerFactory.getLogger(IMSUserManagement.class);
Expand Down Expand Up @@ -199,18 +204,31 @@ public String getLabel() {
public void updateGroups(Collection<AuthorizableConfigBean> groupConfigs) throws IOException {
List<ActionCommand> actionCommands = new LinkedList<>();
for (AuthorizableConfigBean groupConfig : groupConfigs) {
UserGroupActionCommand actionCommand = new UserGroupActionCommand(groupConfig.getAuthorizableId());
ActionCommand actionCommand = new UserGroupActionCommand(groupConfig.getAuthorizableId());
CreateGroupStep createGroupStep = new CreateGroupStep();
createGroupStep.description = groupConfig.getDescription();
actionCommand.addStep(createGroupStep);
// optionally maintain product profile memberships in the group as well
if (config.productProfiles() != null && config.productProfiles().length > 0) {
AddMembershipStep addMembershipStep = new AddMembershipStep();
addMembershipStep.productProfileIds = new HashSet<>(Arrays.asList(config.productProfiles()));
actionCommand.addStep(addMembershipStep);
AddGroupMembers addMembers = new AddGroupMembers();
addMembers.productProfileIds = new HashSet<>(Arrays.asList(config.productProfiles()));
actionCommand.addStep(addMembers);
}
actionCommands.add(actionCommand);
}
// optionally make users group administrators
if (config.groupAdmins() != null && config.groupAdmins().length > 0) {
Set<String> adminGroupNames = groupConfigs.stream()
.map(AuthorizableConfigBean::getAuthorizableId)
.map(id -> "_admin_" + id) // https://adobe-apiplatform.github.io/umapi-documentation/en/api/ActionsCmds.html#addRemoveAttr
.collect(Collectors.toSet());
for (String groupAdmin : config.groupAdmins()) {
ActionCommand actionCommand = new UserActionCommand(groupAdmin);
AddGroupMembership addGroupMembership = new AddGroupMembership(adminGroupNames);
actionCommand.addStep(addGroupMembership);
actionCommands.add(actionCommand);
}
}
// update in batches of 10 commands
AtomicInteger counter = new AtomicInteger();
final Collection<List<ActionCommand>> actionCommandsBatches = actionCommands.stream().collect(Collectors.groupingBy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;

/** Maintains members of groups, to be used with {@link UserGroupActionCommand}.
* For maintaining group administrators use {@link AddGroupMembership}.
*/
@JsonTypeName("add")
@JsonInclude(Include.NON_EMPTY) // neither empty strings nor null values are allowed for the fields
public class AddMembershipStep implements Step {
public class AddGroupMembers implements Step {

@JsonProperty("user")
public Set<String> userIds;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package biz.netcentric.cq.tools.actool.ims.request;

/*-
* #%L
* Access Control Tool Bundle
* %%
* Copyright (C) 2015 - 2024 Cognizant Netcentric
* %%
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* #L%
*/

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;

/** Maintains memberships of users in (admin) groups, to be used with {@link UserActionCommand}.
* @see AddGroupMembers
*/
@JsonTypeName("add")
@JsonInclude(Include.NON_EMPTY) // neither empty strings nor null values are allowed for the fields
public class AddGroupMembership implements Step {

public AddGroupMembership(Collection<String> group) {
this.group = new HashSet<>(group);
}

@JsonProperty("group")
public Set<String> group;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package biz.netcentric.cq.tools.actool.ims.request;

/*-
* #%L
* Access Control Tool Bundle
* %%
* Copyright (C) 2015 - 2024 Cognizant Netcentric
* %%
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* #L%
*/

import com.fasterxml.jackson.annotation.JsonProperty;

public class UserActionCommand extends ActionCommand {

public UserActionCommand(String user) {
this.user = user;
}

@JsonProperty("user")
String user;
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public HttpClientBuilder newBuilder() {

@Test
void testGroupWithInvalidProductProfileMembership() throws IOException {
properties.put("productProfiles", "Invalid name");
properties.put("productProfiles", "invalid");
Configuration config = Converters.standardConverter().convert(properties).to(Configuration.class);
IMSUserManagement imsUserManagement = new IMSUserManagement(config, new HttpClientBuilderFactory() {
@Override
Expand All @@ -116,6 +116,22 @@ public HttpClientBuilder newBuilder() {
assertTrue(t.getMessage().contains("error.plc.not_found"), "Exceptions message is supposed to contain 'error.plc.not_found' but was " + t.getMessage());
}

@Test
void testGroupWithAdmin() throws IOException {
properties.put("groupAdmins", getMandatoryEnvironmentVariable("ACTOOL_IMS_IT_USERID"));
Configuration config = Converters.standardConverter().convert(properties).to(Configuration.class);
IMSUserManagement imsUserManagement = new IMSUserManagement(config, new HttpClientBuilderFactory() {
@Override
public HttpClientBuilder newBuilder() {
return HttpClientBuilder.create();
}
});
AuthorizableConfigBean group = new AuthorizableConfigBean();
group.setAuthorizableId("testGroup");
group.setDescription("my description");
imsUserManagement.updateGroups(Collections.singleton(group));
}

private static String getMandatoryEnvironmentVariable(String name) {
String value = System.getenv(name);
if (value == null) {
Expand Down
Loading