Search in sources :

Example 11 with PatchOperation

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);
    }
}
Also used : Response(javax.ws.rs.core.Response) PatchOperation(io.jans.scim.model.scim2.patch.PatchOperation) UserResource(io.jans.scim.model.scim2.user.UserResource) PatchRequest(io.jans.scim.model.scim2.patch.PatchRequest) InstantMessagingAddress(io.jans.scim.model.scim2.user.InstantMessagingAddress) UserBaseTest(io.jans.scim2.client.UserBaseTest) Test(org.testng.annotations.Test)

Example 12 with PatchOperation

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());
}
Also used : Response(javax.ws.rs.core.Response) ListResponse(io.jans.scim.model.scim2.ListResponse) BulkResponse(io.jans.scim.model.scim2.bulk.BulkResponse) BulkOperation(io.jans.scim.model.scim2.bulk.BulkOperation) BulkRequest(io.jans.scim.model.scim2.bulk.BulkRequest) PatchOperation(io.jans.scim.model.scim2.patch.PatchOperation) BulkResponse(io.jans.scim.model.scim2.bulk.BulkResponse) TypeReference(com.fasterxml.jackson.core.type.TypeReference) PatchRequest(io.jans.scim.model.scim2.patch.PatchRequest) Test(org.testng.annotations.Test) BaseTest(io.jans.scim2.client.BaseTest)

Example 13 with PatchOperation

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
    }
}
Also used : Response(javax.ws.rs.core.Response) ListResponse(io.jans.scim.model.scim2.ListResponse) ListResponse(io.jans.scim.model.scim2.ListResponse) UserResource(io.jans.scim.model.scim2.user.UserResource) PatchOperation(io.jans.scim.model.scim2.patch.PatchOperation) PatchRequest(io.jans.scim.model.scim2.patch.PatchRequest) Test(org.testng.annotations.Test) BaseTest(io.jans.scim2.client.BaseTest)

Example 14 with PatchOperation

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;
}
Also used : PatchOperationType(io.jans.scim.model.scim2.patch.PatchOperationType) Attribute(io.jans.scim.model.scim2.annotations.Attribute) HashMap(java.util.HashMap) Extension(io.jans.scim.model.scim2.extensions.Extension) SCIMException(io.jans.scim.model.exception.SCIMException) BaseScimResource(io.jans.scim.model.scim2.BaseScimResource) NullType(javax.lang.model.type.NullType) HashMap(java.util.HashMap) Map(java.util.Map) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Example 15 with PatchOperation

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;
}
Also used : Response(javax.ws.rs.core.Response) SCIMException(io.jans.scim.model.exception.SCIMException) ScimCustomPerson(io.jans.scim.model.scim.ScimCustomPerson) UserResource(io.jans.scim.model.scim2.user.UserResource) PatchOperation(io.jans.scim.model.scim2.patch.PatchOperation) URI(java.net.URI) InvalidAttributeValueException(javax.management.InvalidAttributeValueException) URISyntaxException(java.net.URISyntaxException) SCIMException(io.jans.scim.model.exception.SCIMException) DuplicateEntryException(io.jans.orm.exception.operation.DuplicateEntryException) InvalidAttributeValueException(javax.management.InvalidAttributeValueException) Path(javax.ws.rs.Path) DefaultValue(javax.ws.rs.DefaultValue) HeaderParam(javax.ws.rs.HeaderParam) RefAdjusted(io.jans.scim.service.scim2.interceptor.RefAdjusted) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) ProtectedApi(io.jans.scim.service.filter.ProtectedApi) PATCH(io.jans.scim.ws.rs.scim2.PATCH)

Aggregations

Response (javax.ws.rs.core.Response)13 PatchOperation (io.jans.scim.model.scim2.patch.PatchOperation)10 PatchRequest (io.jans.scim.model.scim2.patch.PatchRequest)8 Test (org.testng.annotations.Test)7 UserResource (io.jans.scim.model.scim2.user.UserResource)6 InvalidAttributeValueException (javax.management.InvalidAttributeValueException)5 SCIMException (io.jans.scim.model.exception.SCIMException)4 BaseTest (io.jans.scim2.client.BaseTest)4 URI (java.net.URI)4 Consumes (javax.ws.rs.Consumes)4 DefaultValue (javax.ws.rs.DefaultValue)4 HeaderParam (javax.ws.rs.HeaderParam)4 Path (javax.ws.rs.Path)4 Produces (javax.ws.rs.Produces)4 GroupResource (io.jans.scim.model.scim2.group.GroupResource)3 ArrayList (java.util.ArrayList)3 ListResponse (org.gluu.oxtrust.model.scim2.ListResponse)3 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 ApiOperation (com.wordnik.swagger.annotations.ApiOperation)2 DuplicateEntryException (io.jans.orm.exception.operation.DuplicateEntryException)2