Search in sources :

Example 1 with Type

use of com.yahoo.elide.core.type.Type in project elide by yahoo.

the class RSQLFilterDialect method parseTypedExpression.

@Override
public Map<String, FilterExpression> parseTypedExpression(String path, MultivaluedMap<String, String> filterParams, String apiVersion) throws ParseException {
    Map<String, FilterExpression> expressionByType = new HashMap<>();
    for (MultivaluedMap.Entry<String, List<String>> entry : filterParams.entrySet()) {
        String paramName = entry.getKey();
        List<String> paramValues = entry.getValue();
        Matcher matcher = TYPED_FILTER_PATTERN.matcher(paramName);
        if (matcher.find()) {
            String typeName = matcher.group(1);
            if (paramValues.size() != 1) {
                throw new ParseException("Exactly one RSQL expression must be defined for type : " + typeName);
            }
            Type entityType = dictionary.getEntityClass(typeName, apiVersion);
            if (entityType == null) {
                throw new ParseException(INVALID_QUERY_PARAMETER + paramName);
            }
            String expressionText = paramValues.get(0);
            FilterExpression filterExpression = parseFilterExpression(expressionText, entityType, true);
            expressionByType.put(typeName, filterExpression);
        } else {
            throw new ParseException(INVALID_QUERY_PARAMETER + paramName);
        }
    }
    return expressionByType;
}
Also used : ArgumentType(com.yahoo.elide.core.dictionary.ArgumentType) TypeHelper.isPrimitiveNumberType(com.yahoo.elide.core.utils.TypeHelper.isPrimitiveNumberType) Type(com.yahoo.elide.core.type.Type) HashMap(java.util.HashMap) Matcher(java.util.regex.Matcher) List(java.util.List) ArrayList(java.util.ArrayList) Argument.getArgumentsFromString(com.yahoo.elide.core.request.Argument.getArgumentsFromString) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) NotFilterExpression(com.yahoo.elide.core.filter.expression.NotFilterExpression) MultivaluedMap(javax.ws.rs.core.MultivaluedMap)

Example 2 with Type

use of com.yahoo.elide.core.type.Type in project elide by yahoo.

the class RSQLFilterDialect method parseGlobalExpression.

@Override
public FilterExpression parseGlobalExpression(String path, MultivaluedMap<String, String> filterParams, String apiVersion) throws ParseException {
    if (filterParams.size() != 1) {
        throw new ParseException(SINGLE_PARAMETER_ONLY);
    }
    MultivaluedMap.Entry<String, List<String>> entry = CollectionUtils.get(filterParams, 0);
    String queryParamName = entry.getKey();
    if (!"filter".equals(queryParamName)) {
        throw new ParseException(INVALID_QUERY_PARAMETER + queryParamName);
    }
    List<String> queryParamValues = entry.getValue();
    if (queryParamValues.size() != 1) {
        throw new ParseException(SINGLE_PARAMETER_ONLY);
    }
    String queryParamValue = queryParamValues.get(0);
    /*
         * Extract the last collection in the URL.
         */
    String normalizedPath = JsonApiParser.normalizePath(path);
    String[] pathComponents = normalizedPath.split("/");
    String lastPathComponent = pathComponents.length > 0 ? pathComponents[pathComponents.length - 1] : "";
    /*
         * TODO - create a visitor which extracts the type/class of the last path component.
         * This works today by virtue that global filter expressions are only used for root collections
         * and NOT nested associations.
         */
    Type entityType = dictionary.getEntityClass(lastPathComponent, apiVersion);
    if (entityType == null) {
        throw new ParseException("No such collection: " + lastPathComponent);
    }
    return parseFilterExpression(queryParamValue, entityType, true);
}
Also used : ArgumentType(com.yahoo.elide.core.dictionary.ArgumentType) TypeHelper.isPrimitiveNumberType(com.yahoo.elide.core.utils.TypeHelper.isPrimitiveNumberType) Type(com.yahoo.elide.core.type.Type) List(java.util.List) ArrayList(java.util.ArrayList) Argument.getArgumentsFromString(com.yahoo.elide.core.request.Argument.getArgumentsFromString) MultivaluedMap(javax.ws.rs.core.MultivaluedMap)

Example 3 with Type

use of com.yahoo.elide.core.type.Type in project elide by yahoo.

the class DefaultFilterDialect method getPath.

/**
 * Parses [ author, books, publisher, name ] into [(author, books), (book, publisher), (publisher, name)].
 *
 * @param keyParts [ author, books, publisher, name ]
 * @param apiVersion The client requested version.
 * @return [(author, books), (book, publisher), (publisher, name)]
 * @throws ParseException if the filter cannot be parsed
 */
private Path getPath(final String[] keyParts, String apiVersion) throws ParseException {
    if (keyParts == null || keyParts.length <= 0) {
        throw new ParseException("Invalid filter expression");
    }
    List<Path.PathElement> path = new ArrayList<>();
    Type<?>[] types = new Type[keyParts.length];
    String type = keyParts[0];
    types[0] = dictionary.getEntityClass(type, apiVersion);
    if (types[0] == null) {
        throw new ParseException("Unknown entity in filter: " + type);
    }
    /* Extract all the paths for the associations */
    for (int i = 1; i < keyParts.length; ++i) {
        final String field = keyParts[i];
        final Type<?> entityClass = types[i - 1];
        final Type<?> fieldType = ("id".equals(field.toLowerCase(Locale.ENGLISH))) ? dictionary.getIdType(entityClass) : dictionary.getParameterizedType(entityClass, field);
        if (fieldType == null) {
            throw new ParseException("Unknown field in filter: " + field);
        }
        types[i] = fieldType;
    }
    /* Build all the Predicate path elements */
    for (int i = 0; i < types.length - 1; ++i) {
        Type typeClass = types[i];
        String fieldName = keyParts[i + 1];
        Type fieldClass = types[i + 1];
        Path.PathElement pathElement = new Path.PathElement(typeClass, fieldClass, fieldName);
        path.add(pathElement);
    }
    return new Path(path);
}
Also used : Path(com.yahoo.elide.core.Path) Type(com.yahoo.elide.core.type.Type) ArrayList(java.util.ArrayList) ParseException(com.yahoo.elide.core.filter.dialect.ParseException)

Example 4 with Type

use of com.yahoo.elide.core.type.Type in project elide by yahoo.

the class PermissionExpressionBuilder method buildAnyFieldFilterExpression.

/**
 * Build an expression representing any field on an entity.
 *
 * @param forType   Resource class
 * @param requestScope requestScope
 * @return Expressions
 */
public FilterExpression buildAnyFieldFilterExpression(Type<?> forType, RequestScope requestScope, Set<String> requestedFields) {
    Class<? extends Annotation> annotationClass = ReadPermission.class;
    ParseTree classPermissions = entityDictionary.getPermissionsForClass(forType, annotationClass);
    FilterExpression entityFilter = filterExpressionFromParseTree(classPermissions, forType, requestScope);
    // case where the permissions does not have ANY filterExpressionCheck
    if (entityFilter == FALSE_USER_CHECK_EXPRESSION || entityFilter == NO_EVALUATION_EXPRESSION || entityFilter == TRUE_USER_CHECK_EXPRESSION) {
        entityFilter = null;
    }
    FilterExpression allFieldsFilterExpression = entityFilter;
    List<String> fields = entityDictionary.getAllExposedFields(forType).stream().filter(field -> requestedFields == null || requestedFields.contains(field)).collect(Collectors.toList());
    for (String field : fields) {
        ParseTree fieldPermissions = entityDictionary.getPermissionsForField(forType, field, annotationClass);
        FilterExpression fieldExpression = filterExpressionFromParseTree(fieldPermissions, forType, requestScope);
        if (fieldExpression == null && entityFilter == null) {
            // this field will be visible across all instances
            return null;
        }
        if (fieldExpression == null || fieldExpression == FALSE_USER_CHECK_EXPRESSION) {
            // In either case this field is not useful for filtering when loading records
            continue;
        }
        if (fieldExpression == NO_EVALUATION_EXPRESSION || fieldExpression == TRUE_USER_CHECK_EXPRESSION) {
            // When the expression is TRUE_USER_CHECK_EXPRESSION all records can be loaded
            return null;
        }
        if (allFieldsFilterExpression != null) {
            allFieldsFilterExpression = new OrFilterExpression(allFieldsFilterExpression, fieldExpression);
        } else {
            allFieldsFilterExpression = fieldExpression;
        }
    }
    return allFieldsFilterExpression;
}
Also used : CheckExpression(com.yahoo.elide.core.security.permissions.expressions.CheckExpression) PermissionExpressionNormalizationVisitor(com.yahoo.elide.core.security.visitors.PermissionExpressionNormalizationVisitor) OrExpression(com.yahoo.elide.core.security.permissions.expressions.OrExpression) Function(java.util.function.Function) FAILURE(com.yahoo.elide.core.security.permissions.expressions.Expression.Results.FAILURE) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) SpecificFieldExpression(com.yahoo.elide.core.security.permissions.expressions.SpecificFieldExpression) PersistentResource(com.yahoo.elide.core.PersistentResource) PermissionExpressionVisitor(com.yahoo.elide.core.security.visitors.PermissionExpressionVisitor) ParseTree(org.antlr.v4.runtime.tree.ParseTree) NO_EVALUATION_EXPRESSION(com.yahoo.elide.core.security.visitors.PermissionToFilterExpressionVisitor.NO_EVALUATION_EXPRESSION) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) RequestScope(com.yahoo.elide.core.RequestScope) ChangeSpec(com.yahoo.elide.core.security.ChangeSpec) Check(com.yahoo.elide.core.security.checks.Check) PermissionToFilterExpressionVisitor(com.yahoo.elide.core.security.visitors.PermissionToFilterExpressionVisitor) AndExpression(com.yahoo.elide.core.security.permissions.expressions.AndExpression) AnyFieldExpression(com.yahoo.elide.core.security.permissions.expressions.AnyFieldExpression) Set(java.util.Set) Collectors(java.util.stream.Collectors) EntityDictionary(com.yahoo.elide.core.dictionary.EntityDictionary) Expression(com.yahoo.elide.core.security.permissions.expressions.Expression) List(java.util.List) ReadPermission(com.yahoo.elide.annotation.ReadPermission) Type(com.yahoo.elide.core.type.Type) Annotation(java.lang.annotation.Annotation) FALSE_USER_CHECK_EXPRESSION(com.yahoo.elide.core.security.visitors.PermissionToFilterExpressionVisitor.FALSE_USER_CHECK_EXPRESSION) TRUE_USER_CHECK_EXPRESSION(com.yahoo.elide.core.security.visitors.PermissionToFilterExpressionVisitor.TRUE_USER_CHECK_EXPRESSION) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) ReadPermission(com.yahoo.elide.annotation.ReadPermission) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) ParseTree(org.antlr.v4.runtime.tree.ParseTree)

Example 5 with Type

use of com.yahoo.elide.core.type.Type in project elide by yahoo.

the class ActivePermissionExecutor method checkPermissions.

/**
 * First attempts to check user permissions (by looking in the cache and if not present by executing user
 * permissions).  If user permissions don't short circuit the check, run the provided expression executor.
 *
 * @param <A> type parameter
 * @param resourceClass Resource class
 * @param annotationClass Annotation class
 * @param fields Set of all field names that is being accessed
 * @param expressionSupplier Builds a permission expression.
 * @param expressionExecutor Evaluates the expression (post user check evaluation)
 */
protected <A extends Annotation> ExpressionResult checkPermissions(Type<?> resourceClass, Class<A> annotationClass, Set<String> fields, Supplier<Expression> expressionSupplier, Optional<Function<Expression, ExpressionResult>> expressionExecutor) {
    // If the user check has already been evaluated before, return the result directly and save the building cost
    ImmutableSet<String> immutableFields = fields == null ? null : ImmutableSet.copyOf(fields);
    ExpressionResult expressionResult = userPermissionCheckCache.get(Triple.of(annotationClass, resourceClass, immutableFields));
    if (expressionResult == PASS) {
        return expressionResult;
    }
    Expression expression = expressionSupplier.get();
    if (expressionResult == null) {
        expressionResult = executeExpressions(expression, annotationClass, Expression.EvaluationMode.USER_CHECKS_ONLY);
        userPermissionCheckCache.put(Triple.of(annotationClass, resourceClass, immutableFields), expressionResult);
        if (expressionResult == PASS) {
            return expressionResult;
        }
    }
    return expressionExecutor.map(executor -> executor.apply(expression)).orElse(expressionResult);
}
Also used : PASS(com.yahoo.elide.core.security.permissions.ExpressionResult.PASS) Getter(lombok.Getter) HashMap(java.util.HashMap) DEFERRED(com.yahoo.elide.core.security.permissions.ExpressionResult.DEFERRED) PermissionExecutor(com.yahoo.elide.core.security.PermissionExecutor) Function(java.util.function.Function) Supplier(java.util.function.Supplier) UpdatePermission(com.yahoo.elide.annotation.UpdatePermission) DeletePermission(com.yahoo.elide.annotation.DeletePermission) PermissionExpressionBuilder(com.yahoo.elide.core.security.permissions.PermissionExpressionBuilder) Map(java.util.Map) PersistentResource(com.yahoo.elide.core.PersistentResource) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) Triple(org.apache.commons.lang3.tuple.Triple) RequestScope(com.yahoo.elide.core.RequestScope) ChangeSpec(com.yahoo.elide.core.security.ChangeSpec) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Expression(com.yahoo.elide.core.security.permissions.expressions.Expression) ForbiddenAccessException(com.yahoo.elide.core.exceptions.ForbiddenAccessException) ExpressionResult(com.yahoo.elide.core.security.permissions.ExpressionResult) Slf4j(lombok.extern.slf4j.Slf4j) ReadPermission(com.yahoo.elide.annotation.ReadPermission) ExpressionResultCache(com.yahoo.elide.core.security.permissions.ExpressionResultCache) CreatePermission(com.yahoo.elide.annotation.CreatePermission) Type(com.yahoo.elide.core.type.Type) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) Queue(java.util.Queue) AllArgsConstructor(lombok.AllArgsConstructor) Collections(java.util.Collections) FAIL(com.yahoo.elide.core.security.permissions.ExpressionResult.FAIL) NonTransferable(com.yahoo.elide.annotation.NonTransferable) ExpressionResult(com.yahoo.elide.core.security.permissions.ExpressionResult) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) Expression(com.yahoo.elide.core.security.permissions.expressions.Expression)

Aggregations

Type (com.yahoo.elide.core.type.Type)35 EntityDictionary (com.yahoo.elide.core.dictionary.EntityDictionary)22 Set (java.util.Set)17 List (java.util.List)16 Map (java.util.Map)16 ClassType (com.yahoo.elide.core.type.ClassType)15 Function (java.util.function.Function)14 FilterExpression (com.yahoo.elide.core.filter.expression.FilterExpression)13 Annotation (java.lang.annotation.Annotation)12 Collectors (java.util.stream.Collectors)12 Collection (java.util.Collection)11 ReadPermission (com.yahoo.elide.annotation.ReadPermission)10 ArrayList (java.util.ArrayList)10 HashSet (java.util.HashSet)10 DataStoreTransaction (com.yahoo.elide.core.datastore.DataStoreTransaction)9 Optional (java.util.Optional)9 RequestScope (com.yahoo.elide.core.RequestScope)8 Objects (java.util.Objects)8 Path (com.yahoo.elide.core.Path)7 RelationshipType (com.yahoo.elide.core.dictionary.RelationshipType)7