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;
}
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());
}
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());
}
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));
}
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());
}
Aggregations