Search in sources :

Example 1 with PermissionExecutor

use of com.yahoo.elide.core.security.PermissionExecutor in project elide by yahoo.

the class VerifyFieldAccessFilterExpressionVisitor method visitPredicate.

/**
 * Enforce ReadPermission on provided query filter.
 *
 * @return true if allowed, false if rejected
 */
@Override
public Boolean visitPredicate(FilterPredicate filterPredicate) {
    RequestScope requestScope = resource.getRequestScope();
    Set<PersistentResource> val = Collections.singleton(resource);
    PermissionExecutor permissionExecutor = requestScope.getPermissionExecutor();
    ExpressionResult result = permissionExecutor.evaluateFilterJoinUserChecks(resource, filterPredicate);
    if (result == ExpressionResult.UNEVALUATED) {
        result = evaluateUserChecks(filterPredicate, permissionExecutor);
    }
    if (result == ExpressionResult.PASS) {
        return true;
    }
    if (result == ExpressionResult.FAIL) {
        return false;
    }
    for (PathElement element : filterPredicate.getPath().getPathElements()) {
        String fieldName = element.getFieldName();
        if ("this".equals(fieldName)) {
            continue;
        }
        try {
            val = val.stream().filter(Objects::nonNull).flatMap(x -> getValueChecked(x, fieldName, requestScope).toList(LinkedHashSet::new).blockingGet().stream()).filter(Objects::nonNull).collect(Collectors.toSet());
        } catch (ForbiddenAccessException e) {
            result = permissionExecutor.handleFilterJoinReject(filterPredicate, element, e);
            if (result == ExpressionResult.DEFERRED) {
                continue;
            }
            // pass or fail
            return result == ExpressionResult.PASS;
        }
    }
    return true;
}
Also used : FilterExpressionVisitor(com.yahoo.elide.core.filter.expression.FilterExpressionVisitor) FilterPredicate(com.yahoo.elide.core.filter.predicates.FilterPredicate) NotFilterExpression(com.yahoo.elide.core.filter.expression.NotFilterExpression) Set(java.util.Set) EntityProjection(com.yahoo.elide.core.request.EntityProjection) PermissionExecutor(com.yahoo.elide.core.security.PermissionExecutor) Collectors(java.util.stream.Collectors) EntityDictionary(com.yahoo.elide.core.dictionary.EntityDictionary) Objects(java.util.Objects) ForbiddenAccessException(com.yahoo.elide.core.exceptions.ForbiddenAccessException) ExpressionResult(com.yahoo.elide.core.security.permissions.ExpressionResult) ReadPermission(com.yahoo.elide.annotation.ReadPermission) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) PersistentResource(com.yahoo.elide.core.PersistentResource) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) Relationship(com.yahoo.elide.core.request.Relationship) Observable(io.reactivex.Observable) PathElement(com.yahoo.elide.core.Path.PathElement) RelationshipType(com.yahoo.elide.core.dictionary.RelationshipType) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) Collections(java.util.Collections) LinkedHashSet(java.util.LinkedHashSet) RequestScope(com.yahoo.elide.core.RequestScope) LinkedHashSet(java.util.LinkedHashSet) PersistentResource(com.yahoo.elide.core.PersistentResource) PathElement(com.yahoo.elide.core.Path.PathElement) ExpressionResult(com.yahoo.elide.core.security.permissions.ExpressionResult) PermissionExecutor(com.yahoo.elide.core.security.PermissionExecutor) Objects(java.util.Objects) RequestScope(com.yahoo.elide.core.RequestScope) ForbiddenAccessException(com.yahoo.elide.core.exceptions.ForbiddenAccessException)

Example 2 with PermissionExecutor

use of com.yahoo.elide.core.security.PermissionExecutor in project elide by yahoo.

the class VerifyFieldAccessFilterExpressionVisitorTest method testCustomFilterJoin.

@Test
public void testCustomFilterJoin() throws Exception {
    RSQLFilterDialect dialect = RSQLFilterDialect.builder().dictionary(scope.getDictionary()).build();
    FilterExpression expression = dialect.parseFilterExpression("genre==foo", ClassType.of(Book.class), true);
    Book book = new Book();
    PersistentResource<Book> resource = new PersistentResource<>(book, "", scope);
    PermissionExecutor permissionExecutor = scope.getPermissionExecutor();
    DataStoreTransaction tx = scope.getTransaction();
    when(permissionExecutor.checkUserPermissions(ClassType.of(Book.class), ReadPermission.class, GENRE)).thenReturn(ExpressionResult.DEFERRED);
    when(permissionExecutor.checkSpecificFieldPermissions(resource, null, ReadPermission.class, GENRE)).thenThrow(new ForbiddenAccessException(ReadPermission.class));
    when(permissionExecutor.evaluateFilterJoinUserChecks(any(), any())).thenReturn(ExpressionResult.DEFERRED);
    when(permissionExecutor.handleFilterJoinReject(any(), any(), any())).thenAnswer(invocation -> {
        FilterPredicate filterPredicate = invocation.getArgument(0);
        PathElement pathElement = invocation.getArgument(1);
        ForbiddenAccessException reason = invocation.getArgument(2);
        assertEquals("Book", pathElement.getType().getSimpleName());
        assertEquals(GENRE, filterPredicate.getField());
        assertEquals("book.genre IN [foo]", filterPredicate.toString());
        // custom processing
        return "Book".equals(pathElement.getType().getSimpleName()) && filterPredicate.toString().matches("book.genre IN \\[\\w+\\]") && reason.getLoggedMessage().matches(".*Message=ReadPermission Denied.*\\n.*") ? ExpressionResult.DEFERRED : ExpressionResult.FAIL;
    });
    VerifyFieldAccessFilterExpressionVisitor visitor = new VerifyFieldAccessFilterExpressionVisitor(resource);
    // restricted HOME field
    assertTrue(expression.accept(visitor));
    verify(permissionExecutor, times(1)).evaluateFilterJoinUserChecks(any(), any());
    verify(permissionExecutor, times(1)).checkSpecificFieldPermissions(resource, null, ReadPermission.class, GENRE);
    verify(permissionExecutor, never()).checkUserPermissions(any(), any(), isA(String.class));
    verify(permissionExecutor, times(1)).handleFilterJoinReject(any(), any(), any());
    verify(tx, never()).getToManyRelation(any(), any(), any(), any());
}
Also used : PersistentResource(com.yahoo.elide.core.PersistentResource) PermissionExecutor(com.yahoo.elide.core.security.PermissionExecutor) ForbiddenAccessException(com.yahoo.elide.core.exceptions.ForbiddenAccessException) PathElement(com.yahoo.elide.core.Path.PathElement) Book(example.Book) DataStoreTransaction(com.yahoo.elide.core.datastore.DataStoreTransaction) FilterPredicate(com.yahoo.elide.core.filter.predicates.FilterPredicate) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) NotFilterExpression(com.yahoo.elide.core.filter.expression.NotFilterExpression) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) ReadPermission(com.yahoo.elide.annotation.ReadPermission) RSQLFilterDialect(com.yahoo.elide.core.filter.dialect.RSQLFilterDialect) Test(org.junit.jupiter.api.Test)

Example 3 with PermissionExecutor

use of com.yahoo.elide.core.security.PermissionExecutor in project elide by yahoo.

the class VerifyFieldAccessFilterExpressionVisitorTest method testReject.

@Test
public void testReject() {
    Path p1Path = new Path(Arrays.asList(new PathElement(Book.class, Author.class, AUTHORS), new PathElement(Author.class, String.class, NAME)));
    FilterPredicate p1 = new InPredicate(p1Path, "foo", "bar");
    Path p2Path = new Path(Arrays.asList(new PathElement(Book.class, String.class, HOME)));
    FilterPredicate p2 = new InPredicate(p2Path, "blah");
    Path p3Path = new Path(Arrays.asList(new PathElement(Book.class, String.class, GENRE)));
    FilterPredicate p3 = new InPredicate(p3Path, SCIFI);
    // P4 is a duplicate of P3
    Path p4Path = new Path(Arrays.asList(new PathElement(Book.class, String.class, GENRE)));
    FilterPredicate p4 = new InPredicate(p4Path, SCIFI);
    OrFilterExpression or = new OrFilterExpression(p2, p3);
    AndFilterExpression and1 = new AndFilterExpression(or, p1);
    AndFilterExpression and2 = new AndFilterExpression(and1, p4);
    NotFilterExpression not = new NotFilterExpression(and2);
    Book book = new Book();
    Author author = new Author();
    book.setAuthors(Collections.singleton(author));
    author.setBooks(Collections.singleton(book));
    PersistentResource<Book> resource = new PersistentResource<>(book, "", scope);
    PermissionExecutor permissionExecutor = scope.getPermissionExecutor();
    when(permissionExecutor.checkSpecificFieldPermissions(resource, null, ReadPermission.class, HOME)).thenThrow(ForbiddenAccessException.class);
    VerifyFieldAccessFilterExpressionVisitor visitor = new VerifyFieldAccessFilterExpressionVisitor(resource);
    // restricted HOME field
    assertFalse(not.accept(visitor));
    assertFalse(and1.accept(visitor));
    assertFalse(and2.accept(visitor));
    assertFalse(or.accept(visitor));
    assertFalse(p2.accept(visitor));
    // unrestricted fields
    assertTrue(p1.accept(visitor));
    assertTrue(p3.accept(visitor));
    assertTrue(p4.accept(visitor));
    verify(permissionExecutor, times(8)).evaluateFilterJoinUserChecks(any(), any());
    verify(permissionExecutor, times(5)).checkSpecificFieldPermissions(resource, null, ReadPermission.class, HOME);
    verify(permissionExecutor, times(9)).checkUserPermissions(any(), any(), isA(String.class));
    verify(permissionExecutor, times(5)).handleFilterJoinReject(any(), any(), any());
}
Also used : Path(com.yahoo.elide.core.Path) PersistentResource(com.yahoo.elide.core.PersistentResource) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) PermissionExecutor(com.yahoo.elide.core.security.PermissionExecutor) InPredicate(com.yahoo.elide.core.filter.predicates.InPredicate) NotFilterExpression(com.yahoo.elide.core.filter.expression.NotFilterExpression) PathElement(com.yahoo.elide.core.Path.PathElement) Book(example.Book) Author(example.Author) FilterPredicate(com.yahoo.elide.core.filter.predicates.FilterPredicate) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) Test(org.junit.jupiter.api.Test)

Example 4 with PermissionExecutor

use of com.yahoo.elide.core.security.PermissionExecutor in project elide by yahoo.

the class VerifyFieldAccessFilterExpressionVisitorTest method testUserChecksDeferred.

@Test
public void testUserChecksDeferred() throws Exception {
    RSQLFilterDialect dialect = RSQLFilterDialect.builder().dictionary(scope.getDictionary()).build();
    FilterExpression expression = dialect.parseFilterExpression("authors.homeAddress==main", ClassType.of(Book.class), true);
    Book book = new Book();
    Author author = new Author();
    book.setAuthors(Collections.singleton(author));
    author.setBooks(Collections.singleton(book));
    PersistentResource<Book> resource = new PersistentResource<>(book, "", scope);
    PersistentResource<Author> resourceAuthor = new PersistentResource<>(author, "", scope);
    PermissionExecutor permissionExecutor = scope.getPermissionExecutor();
    DataStoreTransaction tx = scope.getTransaction();
    when(permissionExecutor.checkUserPermissions(ClassType.of(Book.class), ReadPermission.class, AUTHORS)).thenReturn(ExpressionResult.PASS);
    when(permissionExecutor.checkSpecificFieldPermissionsDeferred(resource, null, ReadPermission.class, AUTHORS)).thenReturn(ExpressionResult.PASS);
    when(permissionExecutor.getReadPermissionFilter(ClassType.of(Author.class), null)).thenReturn(Optional.empty());
    when(permissionExecutor.checkUserPermissions(ClassType.of(Author.class), ReadPermission.class, HOME)).thenReturn(ExpressionResult.DEFERRED);
    when(permissionExecutor.checkSpecificFieldPermissions(resourceAuthor, null, ReadPermission.class, HOME)).thenThrow(ForbiddenAccessException.class);
    when(tx.getToManyRelation(eq(tx), eq(book), any(), eq(scope))).thenReturn(new DataStoreIterableBuilder(book.getAuthors()).build());
    VerifyFieldAccessFilterExpressionVisitor visitor = new VerifyFieldAccessFilterExpressionVisitor(resource);
    // restricted HOME field
    assertFalse(expression.accept(visitor));
    verify(permissionExecutor, times(1)).evaluateFilterJoinUserChecks(any(), any());
    verify(permissionExecutor, times(1)).checkUserPermissions(ClassType.of(Book.class), ReadPermission.class, AUTHORS);
    verify(permissionExecutor, times(1)).getReadPermissionFilter(ClassType.of(Author.class), new HashSet<>());
    verify(permissionExecutor, times(1)).checkUserPermissions(ClassType.of(Author.class), ReadPermission.class, HOME);
    verify(permissionExecutor, times(1)).checkSpecificFieldPermissions(resourceAuthor, null, ReadPermission.class, HOME);
    verify(permissionExecutor, times(2)).checkUserPermissions(any(), any(), isA(String.class));
    verify(permissionExecutor, times(1)).handleFilterJoinReject(any(), any(), any());
    verify(tx, times(1)).getToManyRelation(eq(tx), eq(book), any(), eq(scope));
}
Also used : PersistentResource(com.yahoo.elide.core.PersistentResource) DataStoreIterableBuilder(com.yahoo.elide.core.datastore.DataStoreIterableBuilder) PermissionExecutor(com.yahoo.elide.core.security.PermissionExecutor) Book(example.Book) Author(example.Author) DataStoreTransaction(com.yahoo.elide.core.datastore.DataStoreTransaction) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) NotFilterExpression(com.yahoo.elide.core.filter.expression.NotFilterExpression) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) RSQLFilterDialect(com.yahoo.elide.core.filter.dialect.RSQLFilterDialect) Test(org.junit.jupiter.api.Test)

Example 5 with PermissionExecutor

use of com.yahoo.elide.core.security.PermissionExecutor in project elide by yahoo.

the class VerifyFieldAccessFilterExpressionVisitorTest method testShortCircuitRejectDeferThenFail.

@Test
public void testShortCircuitRejectDeferThenFail() throws Exception {
    RSQLFilterDialect dialect = RSQLFilterDialect.builder().dictionary(scope.getDictionary()).build();
    FilterExpression expression = dialect.parseFilterExpression("authors.homeAddress==main", ClassType.of(Book.class), true);
    Book book = new Book();
    Author author = new Author();
    book.setAuthors(Collections.singleton(author));
    author.setBooks(Collections.singleton(book));
    PersistentResource<Book> resource = new PersistentResource<>(book, "", scope);
    PermissionExecutor permissionExecutor = scope.getPermissionExecutor();
    DataStoreTransaction tx = scope.getTransaction();
    when(permissionExecutor.checkUserPermissions(ClassType.of(Book.class), ReadPermission.class, AUTHORS)).thenReturn(ExpressionResult.DEFERRED);
    when(permissionExecutor.checkUserPermissions(ClassType.of(Author.class), ReadPermission.class, HOME)).thenThrow(ForbiddenAccessException.class);
    VerifyFieldAccessFilterExpressionVisitor visitor = new VerifyFieldAccessFilterExpressionVisitor(resource);
    // restricted HOME field
    assertFalse(expression.accept(visitor));
    verify(permissionExecutor, times(1)).evaluateFilterJoinUserChecks(any(), any());
    verify(permissionExecutor, times(1)).checkUserPermissions(ClassType.of(Book.class), ReadPermission.class, AUTHORS);
    verify(permissionExecutor, never()).getReadPermissionFilter(ClassType.of(Author.class), null);
    verify(permissionExecutor, times(1)).checkUserPermissions(ClassType.of(Author.class), ReadPermission.class, HOME);
    verify(permissionExecutor, never()).checkSpecificFieldPermissions(any(), any(), any(), any());
    verify(permissionExecutor, never()).checkSpecificFieldPermissionsDeferred(any(), any(), any(), any());
    verify(permissionExecutor, times(2)).checkUserPermissions(any(), any(), isA(String.class));
    verify(permissionExecutor, times(1)).handleFilterJoinReject(any(), any(), any());
    verify(tx, never()).getToManyRelation(any(), any(), any(), any());
}
Also used : PersistentResource(com.yahoo.elide.core.PersistentResource) Book(example.Book) PermissionExecutor(com.yahoo.elide.core.security.PermissionExecutor) Author(example.Author) DataStoreTransaction(com.yahoo.elide.core.datastore.DataStoreTransaction) OrFilterExpression(com.yahoo.elide.core.filter.expression.OrFilterExpression) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) NotFilterExpression(com.yahoo.elide.core.filter.expression.NotFilterExpression) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) RSQLFilterDialect(com.yahoo.elide.core.filter.dialect.RSQLFilterDialect) Test(org.junit.jupiter.api.Test)

Aggregations

PermissionExecutor (com.yahoo.elide.core.security.PermissionExecutor)12 PersistentResource (com.yahoo.elide.core.PersistentResource)10 AndFilterExpression (com.yahoo.elide.core.filter.expression.AndFilterExpression)10 NotFilterExpression (com.yahoo.elide.core.filter.expression.NotFilterExpression)10 OrFilterExpression (com.yahoo.elide.core.filter.expression.OrFilterExpression)10 Book (example.Book)9 Test (org.junit.jupiter.api.Test)9 FilterExpression (com.yahoo.elide.core.filter.expression.FilterExpression)8 RSQLFilterDialect (com.yahoo.elide.core.filter.dialect.RSQLFilterDialect)7 DataStoreTransaction (com.yahoo.elide.core.datastore.DataStoreTransaction)6 PathElement (com.yahoo.elide.core.Path.PathElement)5 Author (example.Author)5 FilterPredicate (com.yahoo.elide.core.filter.predicates.FilterPredicate)4 ReadPermission (com.yahoo.elide.annotation.ReadPermission)3 ForbiddenAccessException (com.yahoo.elide.core.exceptions.ForbiddenAccessException)3 Path (com.yahoo.elide.core.Path)2 RequestScope (com.yahoo.elide.core.RequestScope)2 EntityDictionary (com.yahoo.elide.core.dictionary.EntityDictionary)2 InPredicate (com.yahoo.elide.core.filter.predicates.InPredicate)2 ExpressionResult (com.yahoo.elide.core.security.permissions.ExpressionResult)2