use of io.jans.scim.model.scim2.patch.PatchOperation in project jans by JanssenProject.
the class PatchReplaceUserTest method objectPatch.
@Test(dependsOnMethods = "jsonPathPatch2")
public void objectPatch() {
// Create a patch request by supplying a singleton list with one IMS object
InstantMessagingAddress ims = new InstantMessagingAddress();
ims.setDisplay("barbas");
ims.setPrimary(true);
ims.setType("escape");
ims.setValue("bjensen");
PatchOperation op = new PatchOperation();
op.setOperation("replace");
op.setPath("ims");
op.setValue(Collections.singleton(ims));
PatchRequest pr = new PatchRequest();
pr.setOperations(Collections.singletonList(op));
Response response = client.patchUser(pr, user.getId(), null, null);
assertEquals(response.getStatus(), OK.getStatusCode());
UserResource other = response.readEntity(usrClass);
for (int i = 0; i < 2; i++) {
// Verify different info appeared
InstantMessagingAddress newIms = other.getIms().get(0);
assertEquals(newIms.getDisplay(), ims.getDisplay());
assertEquals(newIms.getValue(), ims.getValue());
assertEquals(newIms.getType(), ims.getType());
assertEquals(newIms.getPrimary(), ims.getPrimary());
// Double check
response = client.getUserById(user.getId(), "ims", null);
other = response.readEntity(usrClass);
}
}
use of io.jans.scim.model.scim2.patch.PatchOperation in project jans by JanssenProject.
the class GroupsBulkTest method bulkObject.
@Test(dependsOnMethods = "bulkJson")
public void bulkObject() {
logger.info("Sending a bulk with a patch to insert admin user into group");
// Creates a patch request consisting of adding the admin user to the group created
PatchOperation po = new PatchOperation();
po.setOperation("add");
po.setPath("members.value");
po.setValue(getAdminId());
PatchRequest pr = new PatchRequest();
pr.setOperations(Collections.singletonList(po));
// Creates the bulk operation associated to the patch request
BulkOperation bop = new BulkOperation();
bop.setMethod("PATCH");
bop.setPath("/Groups/" + groupId);
bop.setData(mapper.convertValue(pr, new TypeReference<Map<String, Object>>() {
}));
BulkRequest breq = new BulkRequest();
breq.setOperations(Collections.singletonList(bop));
// Send bulk and check success of processing
Response response = client.processBulkOperations(breq);
assertEquals(response.getStatus(), Status.OK.getStatusCode());
BulkResponse bres = response.readEntity(BulkResponse.class);
assertSuccessfulOps(bres.getOperations());
}
use of io.jans.scim.model.scim2.patch.PatchOperation in project jans by JanssenProject.
the class PairwiseIdentifiersTest method queryAndRemoval.
@Test
public void queryAndRemoval() throws Exception {
// Get a list (of at most 1 user) who has a persisted pairwise identifier
Response response = client.searchUsers("pairwiseIdentifiers pr", null, 1, null, null, "pairwiseIdentifiers, id", null);
assertEquals(response.getStatus(), OK.getStatusCode());
ListResponse lr = response.readEntity(ListResponse.class);
// If the list is empty do nothing (successful test)
if (lr.getItemsPerPage() > 0) {
UserResource user = (UserResource) lr.getResources().get(0);
assertNotNull(user.getPairwiseIdentifiers());
// Prepare the removal of the user's PPIDs
PatchOperation operation = new PatchOperation();
operation.setOperation("remove");
operation.setPath("pairwiseIdentitifers");
PatchRequest pr = new PatchRequest();
pr.setOperations(Collections.singletonList(operation));
response = client.patchUser(pr, user.getId(), "pairwiseIdentifiers", null);
assertEquals(response.getStatus(), OK.getStatusCode());
// Ensure they are not there anymore.
user = response.readEntity(UserResource.class);
assertNull(user.getPairwiseIdentifiers());
// This test does not guarantee the ou=pairwiseIdentifiers sub-branch disappears... only the jsPPID LDAP attribute
}
}
use of io.jans.scim.model.scim2.patch.PatchOperation in project jans by JanssenProject.
the class Scim2PatchService method applyPatchOperation.
public BaseScimResource applyPatchOperation(BaseScimResource resource, PatchOperation operation, Predicate<String> selectionFilterSkipPredicate) throws Exception {
BaseScimResource result = null;
Map<String, Object> genericMap = null;
PatchOperationType opType = operation.getType();
Class<? extends BaseScimResource> clazz = resource.getClass();
String path = operation.getPath();
log.debug("applyPatchOperation of type {}", opType);
// Determine if operation is with value filter
if (StringUtils.isNotEmpty(path) && !operation.getType().equals(PatchOperationType.ADD)) {
Pair<Boolean, String> pair = validateBracketedPath(path);
if (pair.getFirst()) {
String valSelFilter = pair.getSecond();
if (valSelFilter == null) {
throw new SCIMException("Unexpected syntax in value selection filter");
} else {
int i = path.indexOf("[");
String attribute = path.substring(0, i);
i = path.lastIndexOf("].");
String subAttribute = i == -1 ? "" : path.substring(i + 2);
// Abort earlier
if (selectionFilterSkipPredicate.test(valSelFilter)) {
log.info("Patch operation will be skipped");
return resource;
} else {
return applyPatchOperationWithValueFilter(resource, operation, valSelFilter, attribute, subAttribute);
}
}
}
}
if (!opType.equals(PatchOperationType.REMOVE)) {
Object value = operation.getValue();
List<String> extensionUrns = extService.getUrnsOfExtensions(clazz);
if (value instanceof Map) {
genericMap = IntrospectUtil.strObjMap(value);
} else {
// It's an atomic value or an array
if (StringUtils.isEmpty(path)) {
throw new SCIMException("Value(s) supplied for resource not parseable");
}
// Create a simple map and trim the last part of path
String[] subPaths = ScimResourceUtil.splitPath(path, extensionUrns);
genericMap = Collections.singletonMap(subPaths[subPaths.length - 1], value);
if (subPaths.length == 1) {
path = "";
} else {
path = path.substring(0, path.lastIndexOf("."));
}
}
if (StringUtils.isNotEmpty(path)) {
// Visit backwards creating a composite map
String[] subPaths = ScimResourceUtil.splitPath(path, extensionUrns);
for (int i = subPaths.length - 1; i >= 0; i--) {
// Create a string consisting of all subpaths until the i-th
StringBuilder sb = new StringBuilder();
for (int j = 0; j <= i; j++) {
sb.append(subPaths[j]).append(".");
}
Attribute annot = IntrospectUtil.getFieldAnnotation(sb.substring(0, sb.length() - 1), clazz, Attribute.class);
boolean multivalued = !(annot == null || annot.multiValueClass().equals(NullType.class));
Map<String, Object> genericBiggerMap = new HashMap<>();
genericBiggerMap.put(subPaths[i], multivalued ? Collections.singletonList(genericMap) : genericMap);
genericMap = genericBiggerMap;
}
}
log.debug("applyPatchOperation. Generating a ScimResource from generic map: {}", genericMap.toString());
}
// Try parse genericMap as an instance of the resource
ObjectMapper mapper = new ObjectMapper();
BaseScimResource alter = opType.equals(PatchOperationType.REMOVE) ? resource : mapper.convertValue(genericMap, clazz);
List<Extension> extensions = extService.getResourceExtensions(clazz);
switch(operation.getType()) {
case REPLACE:
result = ScimResourceUtil.transferToResourceReplace(alter, resource, extensions);
break;
case ADD:
result = ScimResourceUtil.transferToResourceAdd(alter, resource, extensions);
break;
case REMOVE:
result = ScimResourceUtil.deleteFromResource(alter, operation.getPath(), extensions);
break;
}
return result;
}
use of io.jans.scim.model.scim2.patch.PatchOperation in project jans by JanssenProject.
the class UserWebService method patchUser.
@Path("{id}")
@PATCH
@Consumes({ MEDIA_TYPE_SCIM_JSON, MediaType.APPLICATION_JSON })
@Produces({ MEDIA_TYPE_SCIM_JSON + UTF8_CHARSET_FRAGMENT, MediaType.APPLICATION_JSON + UTF8_CHARSET_FRAGMENT })
@HeaderParam("Accept")
@DefaultValue(MEDIA_TYPE_SCIM_JSON)
@ProtectedApi(scopes = { "https://jans.io/scim/users.write" })
@RefAdjusted
public Response patchUser(PatchRequest request, @PathParam("id") String id, @QueryParam(QUERY_PARAM_ATTRIBUTES) String attrsList, @QueryParam(QUERY_PARAM_EXCLUDED_ATTRS) String excludedAttrsList) {
Response response;
try {
log.debug("Executing web service method. patchUser");
response = inspectPatchRequest(request, UserResource.class);
if (response != null)
return response;
ScimCustomPerson person = userPersistenceHelper.getPersonByInum(id);
if (person == null)
return notFoundResponse(id, userResourceType);
response = externalConstraintsService.applyEntityCheck(person, request, httpHeaders, uriInfo, HttpMethod.PATCH, userResourceType);
if (response != null)
return response;
UserResource user = new UserResource();
// Fill user instance with all info from person
scim2UserService.transferAttributesToUserResource(person, user, endpointUrl);
// Apply patches one by one in sequence
for (PatchOperation po : request.getOperations()) {
// Handle special case: https://github.com/GluuFederation/oxTrust/issues/800
if (po.getType().equals(REMOVE) && po.getPath().equals("pairwiseIdentifiers")) {
// If this block weren't here, the implementation will throw error because read-only attribute cannot be altered
person.setPpid(null);
user.setPairwiseIdentifiers(null);
scim2UserService.removePPIDsBranch(person.getDn());
} else {
user = (UserResource) scim2PatchService.applyPatchOperation(user, po);
}
}
// Throws exception if final representation does not pass overall validation
log.debug("patchUser. Revising final resource representation still passes validations");
executeValidation(user);
ScimResourceUtil.adjustPrimarySubAttributes(user);
// Update timestamp
user.getMeta().setLastModified(DateUtil.millisToISOString(System.currentTimeMillis()));
// Replaces the information found in person with the contents of user
scim2UserService.replacePersonInfo(person, user, endpointUrl);
String json = resourceSerializer.serialize(user, attrsList, excludedAttrsList);
response = Response.ok(new URI(user.getMeta().getLocation())).entity(json).build();
} catch (InvalidAttributeValueException e) {
log.error(e.getMessage(), e);
response = getErrorResponse(Response.Status.BAD_REQUEST, ErrorScimType.MUTABILITY, e.getMessage());
} catch (SCIMException e) {
response = getErrorResponse(Response.Status.BAD_REQUEST, ErrorScimType.INVALID_SYNTAX, e.getMessage());
} catch (Exception e) {
log.error("Failure at patchUser method", e);
response = getErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Unexpected error: " + e.getMessage());
}
return response;
}
Aggregations