Search in sources :

Example 11 with Attribute

use of io.jans.scim.model.scim2.annotations.Attribute 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 Attribute

use of io.jans.scim.model.scim2.annotations.Attribute 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 Attribute

use of io.jans.scim.model.scim2.annotations.Attribute 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 Attribute

use of io.jans.scim.model.scim2.annotations.Attribute 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 Attribute

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

the class Scim2UserService method transferExtendedAttributesToPerson.

/**
 * Takes all extended attributes found in the SCIM resource and copies them to a
 * ScimCustomPerson This method is called after validations take place (see
 * associated decorator for User Service), so all inputs are OK and can go
 * straight to LDAP with no runtime surprises
 *
 * @param resource
 *            A SCIM resource used as origin of data
 * @param person
 *            a ScimCustomPerson used as destination
 */
private void transferExtendedAttributesToPerson(BaseScimResource resource, ScimCustomPerson person) {
    try {
        // Gets all the extended attributes for this resource
        Map<String, Object> extendedAttrs = resource.getCustomAttributes();
        // Iterates over all extensions this type of resource might have
        for (Extension extension : extService.getResourceExtensions(resource.getClass())) {
            Object val = extendedAttrs.get(extension.getUrn());
            if (val != null) {
                // Obtains the attribute/value(s) pairs in the current extension
                Map<String, Object> attrsMap = IntrospectUtil.strObjMap(val);
                for (String attribute : attrsMap.keySet()) {
                    Object value = attrsMap.get(attribute);
                    if (value == null) {
                        // Attribute was unassigned in this resource: drop it from destination too
                        log.debug("transferExtendedAttributesToPerson. Flushing attribute {}", attribute);
                        person.setAttribute(attribute, (String) null);
                    } else {
                        ExtensionField field = extension.getFields().get(attribute);
                        if (field.isMultiValued()) {
                            person.setCustomAttribute(attribute, extService.getAttributeValues(field, (Collection) value, ldapBackend));
                        } else {
                            person.setCustomAttribute(attribute, extService.getAttributeValue(field, value, ldapBackend));
                        }
                        log.debug("transferExtendedAttributesToPerson. Setting attribute '{}' with values {}", attribute, person.getTypedAttribute(attribute).getDisplayValue());
                    }
                }
            }
        }
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    }
}
Also used : Extension(io.jans.scim.model.scim2.extensions.Extension) ExtensionField(io.jans.scim.model.scim2.extensions.ExtensionField) Collection(java.util.Collection) WebApplicationException(javax.ws.rs.WebApplicationException) InvalidAttributeValueException(javax.management.InvalidAttributeValueException)

Aggregations

Response (javax.ws.rs.core.Response)19 UserResource (io.jans.scim.model.scim2.user.UserResource)13 ListResponse (io.jans.scim.model.scim2.ListResponse)12 Test (org.testng.annotations.Test)12 SCIMException (io.jans.scim.model.exception.SCIMException)11 Attribute (io.jans.scim.model.scim2.annotations.Attribute)11 Field (java.lang.reflect.Field)11 InvalidAttributeValueException (javax.management.InvalidAttributeValueException)11 Attribute (org.gluu.oxtrust.model.scim2.annotations.Attribute)11 ExtensionField (io.jans.scim.model.scim2.extensions.ExtensionField)10 Extension (io.jans.scim.model.scim2.extensions.Extension)9 UserBaseTest (io.jans.scim2.client.UserBaseTest)7 BaseScimResource (io.jans.scim.model.scim2.BaseScimResource)5 NullType (javax.lang.model.type.NullType)5 Path (javax.ws.rs.Path)5 SearchRequest (io.jans.scim.model.scim2.SearchRequest)4 ProtectedApi (io.jans.scim.service.filter.ProtectedApi)4 RefAdjusted (io.jans.scim.service.scim2.interceptor.RefAdjusted)4 BaseTest (io.jans.scim2.client.BaseTest)4 URI (java.net.URI)4