Search in sources :

Example 11 with BaseScimResource

use of io.jans.scim.model.scim2.BaseScimResource in project jans by JanssenProject.

the class BaseScimWebService method inspectPatchRequest.

protected Response inspectPatchRequest(PatchRequest patch, Class<? extends BaseScimResource> cls) {
    Response response = null;
    List<String> schemas = patch.getSchemas();
    if (schemas != null && schemas.size() == 1 && schemas.get(0).equals(PATCH_REQUEST_SCHEMA_ID)) {
        List<PatchOperation> ops = patch.getOperations();
        if (ops != null) {
            // Adjust paths if they came prefixed
            String defSchema = ScimResourceUtil.getDefaultSchemaUrn(cls);
            List<String> urns = extService.getUrnsOfExtensions(cls);
            urns.add(defSchema);
            for (PatchOperation op : ops) {
                if (op.getPath() != null)
                    op.setPath(ScimResourceUtil.adjustNotationInPath(op.getPath(), defSchema, urns));
            }
            for (PatchOperation op : ops) {
                if (op.getType() == null)
                    response = getErrorResponse(BAD_REQUEST, ErrorScimType.INVALID_SYNTAX, "Operation '" + op.getOperation() + "' not recognized");
                else {
                    String path = op.getPath();
                    if (StringUtils.isEmpty(path) && op.getType().equals(PatchOperationType.REMOVE))
                        response = getErrorResponse(BAD_REQUEST, ErrorScimType.NO_TARGET, "Path attribute is required for remove operation");
                    else if (op.getValue() == null && !op.getType().equals(PatchOperationType.REMOVE))
                        response = getErrorResponse(BAD_REQUEST, ErrorScimType.INVALID_SYNTAX, "Value attribute is required for operations other than remove");
                }
                if (response != null)
                    break;
            }
        } else
            response = getErrorResponse(BAD_REQUEST, ErrorScimType.INVALID_SYNTAX, "Patch request MUST contain the attribute 'Operations'");
    } else
        response = getErrorResponse(BAD_REQUEST, ErrorScimType.INVALID_SYNTAX, "Wrong schema(s) supplied in Search Request");
    log.info("inspectPatchRequest. Preprocessing of patch request {}", response == null ? "passed" : "failed");
    return response;
}
Also used : ErrorResponse(io.jans.scim.model.scim2.ErrorResponse) Response(javax.ws.rs.core.Response) ListResponse(io.jans.scim.model.scim2.ListResponse) PatchOperation(io.jans.scim.model.scim2.patch.PatchOperation)

Example 12 with BaseScimResource

use of io.jans.scim.model.scim2.BaseScimResource in project jans by JanssenProject.

the class Scim2PatchService method applyPatchOperationWithValueFilter.

private BaseScimResource applyPatchOperationWithValueFilter(BaseScimResource resource, PatchOperation operation, String valSelFilter, String attribute, String subAttribute) throws SCIMException, InvalidAttributeValueException {
    String path = operation.getPath();
    ObjectMapper mapper = new ObjectMapper();
    Class<? extends BaseScimResource> cls = resource.getClass();
    Map<String, Object> resourceAsMap = mapper.convertValue(resource, new TypeReference<Map<String, Object>>() {
    });
    List<Map<String, Object>> list;
    Attribute attrAnnot = IntrospectUtil.getFieldAnnotation(attribute, cls, Attribute.class);
    if (attrAnnot != null) {
        if (!attrAnnot.multiValueClass().equals(NullType.class) && attrAnnot.type().equals(AttributeDefinition.Type.COMPLEX)) {
            Object colObject = resourceAsMap.get(attribute);
            list = colObject == null ? null : new ArrayList<>((Collection<Map<String, Object>>) colObject);
        } else {
            throw new SCIMException(String.format("Attribute '%s' expected to be complex multi-valued", attribute));
        }
    } else {
        throw new SCIMException(String.format("Attribute '%s' not recognized or expected to be complex multi-valued", attribute));
    }
    if (list == null) {
        log.info("applyPatchOperationWithValueFilter. List of values for {} is empty. Operation has no effect", attribute);
    } else {
        try {
            valSelFilter = FilterUtil.preprocess(valSelFilter, cls);
            ParseTree parseTree = filterService.getParseTree(valSelFilter);
            List<Integer> matchingIndexes = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                if (filterService.complexAttributeMatch(parseTree, list.get(i), attribute, cls)) {
                    // Important: add so that resulting list is reverse-ordered
                    matchingIndexes.add(0, i);
                }
            }
            if (subAttribute.length() > 0 && matchingIndexes.size() > 0 && operation.getType().equals(PatchOperationType.REMOVE)) {
                // per spec (section 3.5.2.2 RFC 7644) subAttribute must not be required or read-only
                Attribute subAttrAnnot = IntrospectUtil.getFieldAnnotation(attribute + "." + subAttribute, cls, Attribute.class);
                if (subAttrAnnot != null && (subAttrAnnot.mutability().equals(READ_ONLY) || subAttrAnnot.isRequired())) {
                    throw new InvalidAttributeValueException("Cannot remove read-only or required attribute " + attribute + "." + subAttribute);
                }
            }
            /*
                Here we differ from spec (see section 3.5.2.3/4 of RFC7644. If no record match is made, we are supposed to
                return error 400 with scimType of noTarget. But this is clearly inconvenient
                */
            log.info("There are {} entries matching the filter '{}'", matchingIndexes.size(), path);
            for (Integer index : matchingIndexes) {
                if (operation.getType().equals(PatchOperationType.REMOVE)) {
                    if (subAttribute.length() == 0) {
                        // Remove the whole item
                        // If intValue is not used, the remove(Object) method is called!
                        list.remove(index.intValue());
                    } else {
                        // remove subattribute only
                        list.get(index).remove(subAttribute);
                    }
                } else {
                    applyPartialUpdate(attribute, subAttribute, list, index, operation.getValue(), cls);
                }
            }
            log.trace("New {} list is:\n{}", attribute, mapper.writeValueAsString(list));
            resourceAsMap.put(attribute, list.isEmpty() ? null : list);
            resource = mapper.convertValue(resourceAsMap, cls);
        } catch (InvalidAttributeValueException ei) {
            throw ei;
        } catch (Exception e) {
            log.info("Error processing Patch operation with value selection path '{}'", path);
            log.error(e.getMessage(), e);
            throw new SCIMException(e.getMessage(), e);
        }
    }
    return resource;
}
Also used : Attribute(io.jans.scim.model.scim2.annotations.Attribute) ArrayList(java.util.ArrayList) InvalidAttributeValueException(javax.management.InvalidAttributeValueException) SCIMException(io.jans.scim.model.exception.SCIMException) InvalidAttributeValueException(javax.management.InvalidAttributeValueException) SCIMException(io.jans.scim.model.exception.SCIMException) HashMap(java.util.HashMap) Map(java.util.Map) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) ParseTree(org.antlr.v4.runtime.tree.ParseTree)

Example 13 with BaseScimResource

use of io.jans.scim.model.scim2.BaseScimResource in project jans by JanssenProject.

the class ExtensionService method getFieldOfExtendedAttribute.

public ExtensionField getFieldOfExtendedAttribute(Class<? extends BaseScimResource> cls, String attribute) {
    List<Extension> extensions = getResourceExtensions(cls);
    ExtensionField field = null;
    try {
        for (Extension ext : extensions) {
            if (attribute.startsWith(ext.getUrn() + ":")) {
                attribute = attribute.substring(ext.getUrn().length() + 1);
                for (ExtensionField f : ext.getFields().values()) if (attribute.equals(f.getName())) {
                    field = f;
                    break;
                }
            }
        }
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    }
    return field;
}
Also used : Extension(io.jans.scim.model.scim2.extensions.Extension) ExtensionField(io.jans.scim.model.scim2.extensions.ExtensionField)

Example 14 with BaseScimResource

use of io.jans.scim.model.scim2.BaseScimResource in project jans by JanssenProject.

the class ExtensionService method getResourceExtensions.

public List<Extension> getResourceExtensions(Class<? extends BaseScimResource> cls) {
    List<Extension> list = new ArrayList<>();
    try {
        // Currently support one extension only for User Resource
        if (cls.equals(UserResource.class)) {
            Map<String, ExtensionField> fields = new HashMap<>();
            for (GluuAttribute attribute : attributeService.getSCIMRelatedAttributes()) {
                if (Optional.ofNullable(attribute.getScimCustomAttr()).orElse(false)) {
                    // first non-null check is needed because certain entries do not have the multivalue attribute set
                    ExtensionField field = new ExtensionField();
                    field.setDescription(attribute.getDescription());
                    field.setType(attribute.getDataType());
                    field.setMultiValued(Optional.ofNullable(attribute.getOxMultiValuedAttribute()).orElse(false));
                    field.setName(attribute.getName());
                    fields.put(attribute.getName(), field);
                }
            }
            String uri = appConfiguration.getUserExtensionSchemaURI();
            if (StringUtils.isEmpty(uri)) {
                uri = USER_EXT_SCHEMA_ID;
            }
            Extension ext = new Extension(uri);
            ext.setFields(fields);
            if (uri.equals(USER_EXT_SCHEMA_ID)) {
                ext.setName(USER_EXT_SCHEMA_NAME);
                ext.setDescription(USER_EXT_SCHEMA_DESCRIPTION);
            }
            list.add(ext);
        }
    } catch (Exception e) {
        log.error("An error ocurred when building extension for {}", cls.getName());
        log.error(e.getMessage(), e);
    }
    return list;
}
Also used : Extension(io.jans.scim.model.scim2.extensions.Extension) ExtensionField(io.jans.scim.model.scim2.extensions.ExtensionField) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) GluuAttribute(io.jans.model.GluuAttribute)

Example 15 with BaseScimResource

use of io.jans.scim.model.scim2.BaseScimResource in project jans by JanssenProject.

the class Scim2GroupService method searchGroups.

public PagedResult<BaseScimResource> searchGroups(String filter, String sortBy, SortOrder sortOrder, int startIndex, int count, String groupsUrl, String usersUrl, int maxCount, boolean fillMembersDisplay) throws Exception {
    Filter ldapFilter = scimFilterParserService.createFilter(filter, Filter.createPresenceFilter("inum"), GroupResource.class);
    log.info("Executing search for groups using: ldapfilter '{}', sortBy '{}', sortOrder '{}', startIndex '{}', count '{}'", ldapFilter.toString(), sortBy, sortOrder.getValue(), startIndex, count);
    PagedResult<GluuGroup> list = ldapEntryManager.findPagedEntries(groupService.getDnForGroup(null), GluuGroup.class, ldapFilter, null, sortBy, sortOrder, startIndex - 1, count, maxCount);
    List<BaseScimResource> resources = new ArrayList<>();
    if (externalScimService.isEnabled() && !externalScimService.executeScimPostSearchGroupsMethods(list)) {
        throw new WebApplicationException("Failed to execute SCIM script successfully", Status.PRECONDITION_FAILED);
    }
    for (GluuGroup group : list.getEntries()) {
        GroupResource scimGroup = new GroupResource();
        transferAttributesToGroupResource(group, scimGroup, fillMembersDisplay, groupsUrl, usersUrl);
        resources.add(scimGroup);
    }
    log.info("Found {} matching entries - returning {}", list.getTotalEntriesCount(), list.getEntries().size());
    PagedResult<BaseScimResource> result = new PagedResult<>();
    result.setEntries(resources);
    result.setTotalEntriesCount(list.getTotalEntriesCount());
    return result;
}
Also used : WebApplicationException(javax.ws.rs.WebApplicationException) Filter(io.jans.orm.search.filter.Filter) BaseScimResource(io.jans.scim.model.scim2.BaseScimResource) ArrayList(java.util.ArrayList) GluuGroup(io.jans.scim.model.GluuGroup) GroupResource(io.jans.scim.model.scim2.group.GroupResource) PagedResult(io.jans.orm.model.PagedResult)

Aggregations

BaseScimResource (io.jans.scim.model.scim2.BaseScimResource)12 Extension (io.jans.scim.model.scim2.extensions.Extension)12 ArrayList (java.util.ArrayList)12 InvalidAttributeValueException (javax.management.InvalidAttributeValueException)12 Response (javax.ws.rs.core.Response)11 SCIMException (io.jans.scim.model.exception.SCIMException)10 BaseScimResource (org.gluu.oxtrust.model.scim2.BaseScimResource)9 URI (java.net.URI)8 ExtensionField (io.jans.scim.model.scim2.extensions.ExtensionField)7 ListResponse (io.jans.scim.model.scim2.ListResponse)6 URISyntaxException (java.net.URISyntaxException)6 ListViewResponse (org.gluu.persist.model.ListViewResponse)6 SearchRequest (io.jans.scim.model.scim2.SearchRequest)5 UserResource (io.jans.scim.model.scim2.user.UserResource)5 PagedResult (io.jans.orm.model.PagedResult)4 Filter (io.jans.orm.search.filter.Filter)4 Attribute (io.jans.scim.model.scim2.annotations.Attribute)4 DefaultValue (javax.ws.rs.DefaultValue)4 GET (javax.ws.rs.GET)4 HeaderParam (javax.ws.rs.HeaderParam)4