![JAR search and dependency download from the Maven repository](/logo.png)
org.cloudfoundry.identity.uaa.scim.endpoints.ScimGroupEndpoints Maven / Gradle / Ivy
/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*******************************************************************************/
package org.cloudfoundry.identity.uaa.scim.endpoints;
import com.jayway.jsonpath.JsonPathException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.resources.AttributeNameMapper;
import org.cloudfoundry.identity.uaa.resources.SearchResults;
import org.cloudfoundry.identity.uaa.resources.SearchResultsFactory;
import org.cloudfoundry.identity.uaa.resources.SimpleAttributeNameMapper;
import org.cloudfoundry.identity.uaa.resources.jdbc.SimpleSearchQueryConverter;
import org.cloudfoundry.identity.uaa.scim.ScimCore;
import org.cloudfoundry.identity.uaa.scim.ScimGroup;
import org.cloudfoundry.identity.uaa.scim.ScimGroupExternalMember;
import org.cloudfoundry.identity.uaa.scim.ScimGroupMember;
import org.cloudfoundry.identity.uaa.scim.ScimGroupMembershipManager;
import org.cloudfoundry.identity.uaa.scim.ScimGroupProvisioning;
import org.cloudfoundry.identity.uaa.scim.exception.InvalidScimResourceException;
import org.cloudfoundry.identity.uaa.scim.exception.MemberAlreadyExistsException;
import org.cloudfoundry.identity.uaa.scim.exception.ScimException;
import org.cloudfoundry.identity.uaa.scim.exception.ScimResourceNotFoundException;
import org.cloudfoundry.identity.uaa.scim.jdbc.JdbcScimGroupExternalMembershipManager;
import org.cloudfoundry.identity.uaa.security.DefaultSecurityContextAccessor;
import org.cloudfoundry.identity.uaa.security.SecurityContextAccessor;
import org.cloudfoundry.identity.uaa.util.UaaPagingUtils;
import org.cloudfoundry.identity.uaa.web.ConvertingExceptionView;
import org.cloudfoundry.identity.uaa.web.ExceptionReport;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static java.util.Optional.ofNullable;
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.LDAP;
import static org.cloudfoundry.identity.uaa.zone.ZoneManagementScopes.ZONE_MANAGING_SCOPE_REGEX;
import static org.springframework.util.StringUtils.hasText;
@Controller
public class ScimGroupEndpoints {
public static final String E_TAG = "ETag";
private final ScimGroupProvisioning dao;
private ScimGroupMembershipManager membershipManager;
private JdbcScimGroupExternalMembershipManager externalMembershipManager;
private Map, HttpStatus> statuses = new HashMap<>();
private HttpMessageConverter>[] messageConverters = new RestTemplate().getMessageConverters().toArray(
new HttpMessageConverter>[0]);
private final Log logger = LogFactory.getLog(getClass());
private SecurityContextAccessor securityContextAccessor = new DefaultSecurityContextAccessor();
private int groupMaxCount;
public void setSecurityContextAccessor(SecurityContextAccessor securityContextAccessor) {
this.securityContextAccessor = securityContextAccessor;
}
public void setStatuses(Map, HttpStatus> statuses) {
this.statuses = statuses;
}
public void setMessageConverters(HttpMessageConverter>[] messageConverters) {
this.messageConverters = messageConverters;
}
public JdbcScimGroupExternalMembershipManager getExternalMembershipManager() {
return externalMembershipManager;
}
public void setExternalMembershipManager(JdbcScimGroupExternalMembershipManager externalMembershipManager) {
this.externalMembershipManager = externalMembershipManager;
}
public ScimGroupEndpoints(ScimGroupProvisioning scimGroupProvisioning, ScimGroupMembershipManager membershipManager) {
this.dao = scimGroupProvisioning;
this.membershipManager = membershipManager;
}
private boolean isMember(ScimGroup group, String userId) {
if (null == userId) {
return true;
}
for (ScimGroupMember member : group.getMembers()) {
if (member.getMemberId().equals(userId)) {
return true;
}
}
return false;
}
private List filterForCurrentUser(List input, int startIndex, int count, boolean includeMembers) {
List response = new ArrayList();
int expectedResponseSize = Math.min(count, input.size());
boolean needMore = response.size() < expectedResponseSize;
while (needMore && startIndex <= input.size()) {
for (ScimGroup group : UaaPagingUtils.subList(input, startIndex, count)) {
if (includeMembers) {
group.setMembers(membershipManager.getMembers(group.getId(), false, IdentityZoneHolder.get().getId()));
}
response.add(group);
needMore = response.size() < expectedResponseSize;
if (!needMore) {
break;
}
}
startIndex += count;
}
return response;
}
@RequestMapping(value = {"/Groups"}, method = RequestMethod.GET)
@ResponseBody
public SearchResults> listGroups(
@RequestParam(value = "attributes", required = false) String attributesCommaSeparated,
@RequestParam(required = false, defaultValue = "id pr") String filter,
@RequestParam(required = false, defaultValue = "created") String sortBy,
@RequestParam(required = false, defaultValue = "ascending") String sortOrder,
@RequestParam(required = false, defaultValue = "1") int startIndex,
@RequestParam(required = false, defaultValue = "100") int count) {
if (count > groupMaxCount) {
count = groupMaxCount;
}
List result;
try {
result = dao.query(filter, sortBy, "ascending".equalsIgnoreCase(sortOrder), IdentityZoneHolder.get().getId());
} catch (IllegalArgumentException e) {
throw new ScimException("Invalid filter expression: [" + filter + "]", HttpStatus.BAD_REQUEST);
}
List input;
if (!StringUtils.hasLength(attributesCommaSeparated)) {
input = filterForCurrentUser(result, startIndex, count, true);
return new SearchResults<>(Arrays.asList(ScimCore.SCHEMAS), input, startIndex, count,
result.size());
}
AttributeNameMapper mapper = new SimpleAttributeNameMapper(Collections.emptyMap());
String[] attributes = attributesCommaSeparated.split(",");
input = filterForCurrentUser(result, startIndex, count, Arrays.asList(attributes).contains("members"));
try {
return SearchResultsFactory.buildSearchResultFrom(input, startIndex, count, result.size(), attributes,
mapper, Arrays.asList(ScimCore.SCHEMAS));
} catch (JsonPathException e) {
throw new ScimException("Invalid attributes: [" + attributesCommaSeparated + "]", HttpStatus.BAD_REQUEST);
}
}
@RequestMapping(value = {"/Groups/External/list"}, method = RequestMethod.GET)
@ResponseBody
@Deprecated
public SearchResults> listExternalGroups(
@RequestParam(required = false, defaultValue = "1") int startIndex,
@RequestParam(required = false, defaultValue = "100") int count,
@RequestParam(required = false, defaultValue = "") String filter) {
return getExternalGroups(startIndex, count, filter, "", "");
}
@RequestMapping(value = {"/Groups/External"}, method = RequestMethod.GET)
@ResponseBody
public SearchResults> getExternalGroups(
@RequestParam(required = false, defaultValue = "1") int startIndex,
@RequestParam(required = false, defaultValue = "100") int count,
@RequestParam(required = false, defaultValue = "") String filter,
@RequestParam(required = false, defaultValue = "") String origin,
@RequestParam(required = false, defaultValue = "") String externalGroup) {
if (hasText(filter)) {
if (hasText(origin) || hasText(externalGroup)) {
throw new ScimException("Deprecated filter parameter may not be used in conjunction with origin or externalGroup parameters", HttpStatus.BAD_REQUEST);
}
SimpleSearchQueryConverter converter = new SimpleSearchQueryConverter();
try {
MultiValueMap filterData = converter.getFilterValues(filter, Arrays.asList("origin", "externalgroup"));
origin = (ofNullable(filterData.getFirst("origin")).orElse(origin)).toString();
externalGroup = (ofNullable(filterData.getFirst("externalGroup")).orElse(externalGroup)).toString();
} catch (IllegalArgumentException e) {
throw new ScimException("Filter not supported, please use origin and externalGroup parameters", e, HttpStatus.BAD_REQUEST);
}
}
List result;
try {
result = new ArrayList(externalMembershipManager.getExternalGroupMappings(IdentityZoneHolder.get().getId()));
} catch (IllegalArgumentException e) {
throw new ScimException("Invalid filter expression: [" + filter + "]", e, HttpStatus.BAD_REQUEST);
}
final String filterOrigin = origin, filterGroup = externalGroup;
result.removeIf(em -> hasText(filterOrigin) && !em.getOrigin().equals(filterOrigin));
result.removeIf(em -> hasText(filterGroup) && !em.getExternalGroup().equals(filterGroup));
return SearchResultsFactory.cropAndBuildSearchResultFrom(
result,
startIndex,
count,
result.size(),
new String[]{"groupId", "displayName", "externalGroup", "origin"},
Arrays.asList(ScimCore.SCHEMAS));
}
@RequestMapping(value = {"/Groups/External"}, method = RequestMethod.POST)
@ResponseBody
@ResponseStatus(HttpStatus.CREATED)
public ScimGroupExternalMember mapExternalGroup(@RequestBody ScimGroupExternalMember sgm) {
try {
String displayName = sgm.getDisplayName();
String groupId = hasText(sgm.getGroupId()) ? sgm.getGroupId() : getGroupId(displayName);
String externalGroup = hasText(sgm.getExternalGroup()) ? sgm.getExternalGroup().trim() : sgm.getExternalGroup();
String origin = hasText(sgm.getOrigin()) ? sgm.getOrigin() : LDAP;
return externalMembershipManager.mapExternalGroup(groupId, externalGroup, origin, IdentityZoneHolder.get().getId());
} catch (IllegalArgumentException e) {
throw new ScimException(e.getMessage(), HttpStatus.BAD_REQUEST);
} catch (ScimResourceNotFoundException e) {
throw new ScimException(e.getMessage(), HttpStatus.NOT_FOUND);
} catch (MemberAlreadyExistsException e) {
throw new ScimException(e.getMessage(), HttpStatus.CONFLICT);
}
}
@RequestMapping(value = {"/Groups/External/groupId/{groupId}/externalGroup/{externalGroup}"}, method = RequestMethod.DELETE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@Deprecated
public ScimGroupExternalMember deprecated2UnmapExternalGroup(@PathVariable String groupId, @PathVariable String externalGroup) {
return unmapExternalGroup(groupId, externalGroup, null);
}
@RequestMapping(value = {"/Groups/External/groupId/{groupId}/externalGroup/{externalGroup}/origin/{origin}"}, method = RequestMethod.DELETE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ScimGroupExternalMember unmapExternalGroup(@PathVariable String groupId,
@PathVariable String externalGroup,
@PathVariable String origin) {
try {
if (!hasText(origin)) {
origin = LDAP;
}
return externalMembershipManager.unmapExternalGroup(groupId, externalGroup.trim(), origin, IdentityZoneHolder.get().getId());
} catch (IllegalArgumentException e) {
throw new ScimException(e.getMessage(), HttpStatus.BAD_REQUEST);
} catch (ScimResourceNotFoundException e) {
throw new ScimException(e.getMessage(), HttpStatus.NOT_FOUND);
} catch (MemberAlreadyExistsException e) {
throw new ScimException(e.getMessage(), HttpStatus.CONFLICT);
}
}
@RequestMapping(value = {"/Groups/External/id/{groupId}/{externalGroup}"}, method = RequestMethod.DELETE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@Deprecated
public ScimGroupExternalMember deprecatedUnmapExternalGroup(@PathVariable String groupId, @PathVariable String externalGroup) {
return unmapExternalGroup(groupId, externalGroup, LDAP);
}
@RequestMapping(value = {"/Groups/External/displayName/{displayName}/externalGroup/{externalGroup}"}, method = RequestMethod.DELETE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@Deprecated
public ScimGroupExternalMember unmapExternalGroupUsingName(@PathVariable String displayName, @PathVariable String externalGroup) {
return unmapExternalGroupUsingName(displayName, externalGroup, LDAP);
}
@RequestMapping(value = {"/Groups/External/displayName/{displayName}/externalGroup/{externalGroup}/origin/{origin}"}, method = RequestMethod.DELETE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ScimGroupExternalMember unmapExternalGroupUsingName(@PathVariable String displayName,
@PathVariable String externalGroup,
@PathVariable String origin) {
try {
if (!hasText(origin)) {
origin = LDAP;
}
return externalMembershipManager.unmapExternalGroup(getGroupId(displayName), externalGroup.trim(), origin, IdentityZoneHolder.get().getId());
} catch (IllegalArgumentException e) {
throw new ScimException(e.getMessage(), HttpStatus.BAD_REQUEST);
} catch (ScimResourceNotFoundException e) {
throw new ScimException(e.getMessage(), HttpStatus.NOT_FOUND);
} catch (MemberAlreadyExistsException e) {
throw new ScimException(e.getMessage(), HttpStatus.CONFLICT);
}
}
@RequestMapping(value = {"/Groups/External/{displayName}/{externalGroup}"}, method = RequestMethod.DELETE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@Deprecated
public ScimGroupExternalMember deprecatedUnmapExternalGroupUsingName(@PathVariable String displayName, @PathVariable String externalGroup) {
return unmapExternalGroupUsingName(displayName, externalGroup);
}
private String getGroupId(String displayName) {
if (displayName == null || displayName.trim().length() == 0) {
throw new ScimException("Group not found, not name provided", HttpStatus.NOT_FOUND);
}
List result = dao.query("displayName eq \"" + displayName + "\"", IdentityZoneHolder.get().getId());
if (result == null || result.size() == 0) {
throw new ScimException("Group not found:" + displayName, HttpStatus.NOT_FOUND);
}
return result.get(0).getId();
}
@RequestMapping(value = {"/Groups/{groupId}"}, method = RequestMethod.GET)
@ResponseBody
public ScimGroup getGroup(@PathVariable String groupId, HttpServletResponse httpServletResponse) {
logger.debug("retrieving group with id: " + groupId);
ScimGroup group = dao.retrieve(groupId, IdentityZoneHolder.get().getId());
group.setMembers(membershipManager.getMembers(groupId, false, IdentityZoneHolder.get().getId()));
addETagHeader(httpServletResponse, group);
return group;
}
@RequestMapping(value = {"/Groups"}, method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public ScimGroup createGroup(@RequestBody ScimGroup group, HttpServletResponse httpServletResponse) {
group.setZoneId(IdentityZoneHolder.get().getId());
ScimGroup created = dao.create(group, IdentityZoneHolder.get().getId());
if (group.getMembers() != null) {
for (ScimGroupMember member : group.getMembers()) {
try {
membershipManager.addMember(created.getId(), member, IdentityZoneHolder.get().getId());
} catch (ScimException ex) {
logger.warn("Attempt to add invalid member: " + member.getMemberId() + " to group: " + created.getId(), ex);
dao.delete(created.getId(), created.getVersion(), IdentityZoneHolder.get().getId());
throw new InvalidScimResourceException("Invalid group member: " + member.getMemberId());
}
}
}
created.setMembers(membershipManager.getMembers(created.getId(), false, IdentityZoneHolder.get().getId()));
addETagHeader(httpServletResponse, created);
return created;
}
@RequestMapping(value = {"/Groups/{groupId}"}, method = RequestMethod.PUT)
@ResponseBody
public ScimGroup updateGroup(@RequestBody ScimGroup group, @PathVariable String groupId,
@RequestHeader(value = "If-Match", required = false) String etag,
HttpServletResponse httpServletResponse) {
if (etag == null) {
throw new ScimException("Missing If-Match for PUT", HttpStatus.BAD_REQUEST);
}
logger.debug("updating group: " + groupId);
int version = getVersion(groupId, etag);
group.setVersion(version);
ScimGroup existing = getGroup(groupId, httpServletResponse);
try {
group.setZoneId(IdentityZoneHolder.get().getId());
ScimGroup updated = dao.update(groupId, group, IdentityZoneHolder.get().getId());
if (group.getMembers() != null && group.getMembers().size() > 0) {
membershipManager.updateOrAddMembers(updated.getId(), group.getMembers(), IdentityZoneHolder.get().getId());
} else {
membershipManager.removeMembersByGroupId(updated.getId(), IdentityZoneHolder.get().getId());
}
updated.setMembers(membershipManager.getMembers(updated.getId(), false, IdentityZoneHolder.get().getId()));
addETagHeader(httpServletResponse, updated);
return updated;
} catch (IncorrectResultSizeDataAccessException ex) {
logger.error("Error updating group, restoring to previous state");
// restore to correct state before reporting error
existing.setVersion(getVersion(groupId, "*"));
dao.update(groupId, existing, IdentityZoneHolder.get().getId());
throw new ScimException(ex.getMessage(), ex, HttpStatus.CONFLICT);
} catch (ScimResourceNotFoundException ex) {
logger.error("Error updating group, restoring to previous state: " + existing);
// restore to correct state before reporting error
existing.setVersion(getVersion(groupId, "*"));
dao.update(groupId, existing, IdentityZoneHolder.get().getId());
throw new ScimException(ex.getMessage(), ex, HttpStatus.BAD_REQUEST);
}
}
@RequestMapping(value = {"/Groups/{groupId}"}, method = RequestMethod.PATCH)
@ResponseBody
public ScimGroup patchGroup(@RequestBody ScimGroup patch, @PathVariable
String groupId,
@RequestHeader(value = "If-Match", required = false) String etag,
HttpServletResponse httpServletResponse) {
if (etag == null) {
throw new ScimException("Missing If-Match for PATCH", HttpStatus.BAD_REQUEST);
}
logger.debug("patching group: " + groupId);
int version = getVersion(groupId, etag);
patch.setVersion(version);
ScimGroup current = getGroup(groupId, httpServletResponse);
current.patch(patch);
return updateGroup(current, groupId, etag, httpServletResponse);
}
@RequestMapping(value = {"/Groups/{groupId}"}, method = RequestMethod.DELETE)
@ResponseBody
public ScimGroup deleteGroup(@PathVariable String groupId,
@RequestHeader(value = "If-Match", required = false, defaultValue = "*") String etag,
HttpServletResponse httpServletResponse) {
ScimGroup group = getGroup(groupId, httpServletResponse);
logger.debug("deleting group: " + group);
try {
membershipManager.removeMembersByGroupId(groupId, IdentityZoneHolder.get().getId());
membershipManager.removeMembersByMemberId(groupId, IdentityZoneHolder.get().getId());
dao.delete(groupId, getVersion(groupId, etag), IdentityZoneHolder.get().getId());
} catch (IncorrectResultSizeDataAccessException ex) {
logger.debug("error deleting group", ex);
throw new ScimException("error deleting group: " + groupId, ex, HttpStatus.CONFLICT);
}
return group;
}
@RequestMapping(value = {"/Groups/zones"}, method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
@Deprecated
public ScimGroup addZoneManagers(@RequestBody ScimGroup group, HttpServletResponse httpServletResponse) {
if (!group.getDisplayName().matches(ZONE_MANAGING_SCOPE_REGEX)) {
throw new ScimException("Invalid group name.", HttpStatus.BAD_REQUEST);
}
if (group.getMembers() == null || group.getMembers().size() == 0) {
throw new ScimException("Invalid group members, you have to add at least one member.", HttpStatus.BAD_REQUEST);
}
try {
ScimGroup existing = getGroup(getGroupId(group.getDisplayName()), httpServletResponse);
List newMembers = new LinkedList<>(existing.getMembers());
//we have an existing group - add new memberships
for (ScimGroupMember member : group.getMembers()) {
if (!isMember(existing, member.getMemberId())) {
newMembers.add(member);
}
}
existing.setMembers(newMembers);
return updateGroup(existing, existing.getId(), String.valueOf(existing.getVersion()), httpServletResponse);
} catch (ScimException ex) {
if (ex.getStatus().equals(HttpStatus.NOT_FOUND)) {
return createGroup(group, httpServletResponse);
} else {
throw ex;
}
}
}
@RequestMapping(value = {"/Groups/zones/{userId}/{zoneId}"}, method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@Deprecated
public ScimGroup deleteZoneAdmin(@PathVariable String userId, @PathVariable String zoneId, HttpServletResponse httpServletResponse) {
return deleteZoneScope(userId, zoneId, "admin", httpServletResponse);
}
@RequestMapping(value = {"/Groups/zones/{userId}/{zoneId}/{scope}"}, method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@Deprecated
public ScimGroup deleteZoneScope(@PathVariable String userId,
@PathVariable String zoneId,
@PathVariable String scope,
HttpServletResponse httpServletResponse) {
String groupName = "zones." + zoneId + "." + scope;
if (!groupName.matches(ZONE_MANAGING_SCOPE_REGEX)) {
throw new ScimException("Invalid group name.", HttpStatus.BAD_REQUEST);
}
String groupId = getGroupId(groupName);
ScimGroup group = getGroup(groupId, httpServletResponse);
if (!hasText(userId) || !hasText(zoneId)) {
throw new ScimException("User ID and Zone ID are required.", HttpStatus.BAD_REQUEST);
}
if (!isMember(group, userId)) {
throw new ScimException("User is not a zone admin.", HttpStatus.NOT_FOUND);
}
List newZoneAdmins = new LinkedList<>();
for (ScimGroupMember member : group.getMembers()) {
if (!member.getMemberId().equals(userId)) {
newZoneAdmins.add(member);
}
}
group.setMembers(newZoneAdmins);
return updateGroup(group, group.getId(), String.valueOf(group.getVersion()), httpServletResponse);
}
@RequestMapping("/Groups/{groupId}/members/{memberId}")
public ResponseEntity getGroupMembership(@PathVariable String groupId, @PathVariable String memberId) {
ScimGroupMember membership = membershipManager.getMemberById(groupId, memberId, IdentityZoneHolder.get().getId());
return new ResponseEntity<>(membership, HttpStatus.OK);
}
@RequestMapping(value = "/Groups/{groupId}/members", method = RequestMethod.GET)
public ResponseEntity> listGroupMemberships(@PathVariable String groupId,
@RequestParam(required = false, defaultValue = "false") boolean returnEntities,
@RequestParam(required = false, defaultValue = "", name = "filter") String deprecatedFilter) {
dao.retrieve(groupId, IdentityZoneHolder.get().getId());
List members = membershipManager.getMembers(groupId, returnEntities, IdentityZoneHolder.get().getId());
return new ResponseEntity<>(members, HttpStatus.OK);
}
@RequestMapping(value = "/Groups/{groupId}/members", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public ScimGroupMember addMemberToGroup(@PathVariable String groupId, @RequestBody ScimGroupMember member) {
return membershipManager.addMember(groupId, member, IdentityZoneHolder.get().getId());
}
@RequestMapping(value = "/Groups/{groupId}/members/{memberId}", method = RequestMethod.DELETE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ScimGroupMember deleteGroupMembership(@PathVariable String groupId, @PathVariable String memberId) {
ScimGroupMember membership = membershipManager.removeMemberById(groupId, memberId, IdentityZoneHolder.get().getId());
return membership;
}
@ExceptionHandler
public View handleException(Exception t, HttpServletRequest request) throws ScimException {
ScimException e = new ScimException("Unexpected error", t, HttpStatus.INTERNAL_SERVER_ERROR);
if (t instanceof ScimException) {
e = (ScimException) t;
} else {
Class> clazz = t.getClass();
for (Class> key : statuses.keySet()) {
if (key.isAssignableFrom(clazz)) {
e = new ScimException(t.getMessage(), t, statuses.get(key));
break;
}
}
}
// User can supply trace=true or just trace (unspecified) to get stack
// traces
boolean trace = request.getParameter("trace") != null && !request.getParameter("trace").equals("false");
return new ConvertingExceptionView(new ResponseEntity(new ExceptionReport(e, trace),
e.getStatus()), messageConverters);
}
private int getVersion(String groupId, String etag) {
String value = etag.trim();
while (value.startsWith("\"")) {
value = value.substring(1);
}
while (value.endsWith("\"")) {
value = value.substring(0, value.length() - 1);
}
if (value.equals("*")) {
return dao.retrieve(groupId, IdentityZoneHolder.get().getId()).getVersion();
}
try {
return Integer.valueOf(value);
} catch (NumberFormatException e) {
throw new ScimException("Invalid version match header (should be a version number): " + etag,
HttpStatus.BAD_REQUEST);
}
}
private void addETagHeader(HttpServletResponse httpServletResponse, ScimGroup scimGroup) {
httpServletResponse.setHeader(E_TAG, "\"" + scimGroup.getVersion() + "\"");
}
public void setGroupMaxCount(int groupMaxCount) {
if (groupMaxCount <= 0) {
throw new IllegalArgumentException(
String.format("Invalid \"groupMaxCount\" value (got %d). Should be positive number.", groupMaxCount)
);
}
this.groupMaxCount = groupMaxCount;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy