Skip to content

Commit

Permalink
[#105] Added setGroups action to the user REST endpoint (#691)
Browse files Browse the repository at this point in the history
Added `setGroups` action to the user REST endpoint. 
Pass group names array in the `groups` request body property 
see the example below:
```bash
curl --location --request POST 'http://openam.example.org:8080/openam/json/realms/root/users/demo?_action=setGroups' \
--header 'Content-Type: application/json' \
--header 'iPlanetDirectoryPro: AQIC5wM2LY4....1MTk4AAJTMQAA*' \
--data-raw '{
    "groups": ["managers", "group1"]
}'
```
  • Loading branch information
maximthomas authored Dec 19, 2023
1 parent ad1fd55 commit 303c2e3
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2012-2016 ForgeRock AS.
* Portions copyright 2023 3A Systems LLC
*/

package org.forgerock.openam.core.rest;
Expand All @@ -22,7 +23,6 @@
import static org.forgerock.json.JsonValue.object;
import static org.forgerock.json.resource.ResourceException.*;
import static org.forgerock.json.resource.Responses.newActionResponse;
import static org.forgerock.json.resource.http.HttpUtils.PROTOCOL_VERSION_1;
import static org.forgerock.openam.core.rest.IdentityRestUtils.*;
import static org.forgerock.openam.core.rest.UserAttributeInfo.*;
import static org.forgerock.openam.rest.RestUtils.*;
Expand Down Expand Up @@ -1013,6 +1013,24 @@ public Promise<ActionResponse, ResourceException> actionInstance(final Context c
debug.warning("Cannot change password! " + resourceId + ":" + re);
return re.asPromise();
}
} else if("setGroups".equalsIgnoreCase(action)) {
RealmContext realmContext = context.asContext(RealmContext.class);
final String realm = realmContext.getRealm().asPath();

JsonValue value = request.getContent();
try {
Set<String> groups = new HashSet<>(value.get("groups").asList(String.class));
IdentityRestUtils.changeMemberships(context, realm, resourceId, groups);
if (debug.messageEnabled()) {
String principalName = PrincipalRestUtils.getPrincipalNameFromServerContext(context);
debug.message("IdentityResource.actionInstance :: ACTION of set groups for " + resourceId
+ " in realm " + realm + " performed by " + principalName);
}
return newResultPromise(newActionResponse(json(object())));
} catch (ResourceException re) {
debug.warning("Cannot set groups! " + resourceId + ":" + re);
return re.asPromise();
}
} else {
return new NotSupportedException(action + " not supported for resource instances").asPromise();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2015-2016 ForgeRock AS.
* Portions copyright 2023 3A Systems LLC
*/
package org.forgerock.openam.core.rest;

Expand All @@ -28,6 +29,7 @@
import com.sun.identity.idsvcs.IdentityDetails;
import com.sun.identity.idsvcs.ListWrapper;
import com.sun.identity.shared.debug.Debug;
import org.apache.commons.collections4.CollectionUtils;
import org.forgerock.guice.core.InjectorHolder;
import org.forgerock.json.JsonValue;
import org.forgerock.json.JsonValueException;
Expand All @@ -53,6 +55,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public final class IdentityRestUtils {

Expand Down Expand Up @@ -94,6 +97,56 @@ public static void changePassword(Context serverContext, String realm, String us
}
}

public static void changeMemberships(Context serverContext, String realm, String username, Set<String> groupNames)
throws ResourceException {
try {
SSOToken token = serverContext.asContext(SSOTokenContext.class).getCallerSSOToken();

//check if groups exist
for(String gn : groupNames) {
AMIdentity groupIdentity = new AMIdentity(token, gn, IdType.GROUP, realm, null);
if(!groupIdentity.isExists()) {
throw new SSOException("group " + gn + " does not exist");
}
}

AMIdentity userIdentity = new AMIdentity(token, username, IdType.USER, realm, null);

Set<String> membershipsToAdd = new HashSet<>(groupNames);
Set<String> membershipsToRemove = new HashSet<>();
Set<AMIdentity> currentMembershipsIdentity = userIdentity.getMemberships(IdType.GROUP);
final Set<String> currentMemberships = CollectionUtils.isNotEmpty(currentMembershipsIdentity)
? currentMembershipsIdentity.stream().map(AMIdentity::getName).collect(Collectors.toSet())
: null;

if (!CollectionUtils.isEmpty(currentMemberships)) {
membershipsToRemove = currentMemberships.stream().filter(cm -> !groupNames.contains(cm)).collect(Collectors.toSet());
membershipsToAdd = groupNames.stream().filter(m -> !currentMemberships.contains(m)).collect(Collectors.toSet());
}

if (!CollectionUtils.isEmpty(membershipsToRemove)) {
for (String idName : membershipsToRemove) {
AMIdentity groupIdentity = new AMIdentity(token, idName, IdType.GROUP, realm, null);
groupIdentity.removeMember(userIdentity);
}
}

if (!CollectionUtils.isEmpty(membershipsToAdd)) {
for (String idName : membershipsToAdd) {
AMIdentity groupIdentity = new AMIdentity(token, idName, IdType.GROUP, realm, null);
groupIdentity.addMember(userIdentity);
}
}

} catch (SSOException ssoe) {
debug.warning("IdentityRestUtils.changeMemberships() :: SSOException occurred while changing "
+ "the groups for user: " + username, ssoe);
throw new PermanentException(401, "An error occurred while trying to change the user groups", ssoe);
} catch (IdRepoException ire) {
throw RESOURCE_MAPPING_HANDLER.handleError(ire);
}
}

public static Map<String, Set<String>> getIdentityServicesAttributes(String realm, String objectType) {
Map<String, Set<String>> identityServicesAttributes = new HashMap<>();
identityServicesAttributes.put("objecttype", Collections.singleton(objectType));
Expand Down

0 comments on commit 303c2e3

Please sign in to comment.