Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor;
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutorContextFactory;
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
import com.introproventures.graphql.jpa.query.schema.RestrictedKeysProvider;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutorContextFactory;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;

import graphql.GraphQL;
import graphql.GraphQLContext;
import graphql.execution.instrumentation.Instrumentation;
Expand All @@ -55,8 +57,13 @@ public static class DefaultGraphQLJpaQueryConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(EntityManagerFactory.class)
public GraphQLSchemaBuilder graphQLJpaSchemaBuilder(final EntityManagerFactory entityManagerFactory) {
return new GraphQLJpaSchemaBuilder(entityManagerFactory.createEntityManager());
public GraphQLSchemaBuilder graphQLJpaSchemaBuilder(final EntityManagerFactory entityManagerFactory,
ObjectProvider<RestrictedKeysProvider> restrictedKeysProvider) {
GraphQLJpaSchemaBuilder bean = new GraphQLJpaSchemaBuilder(entityManagerFactory.createEntityManager());

restrictedKeysProvider.ifAvailable(bean::restrictedKeysProvider);

return bean;
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutionInputFactory;
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor;
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
import com.introproventures.graphql.jpa.query.schema.RestrictedKeysProvider;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutorContextFactory;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
Expand Down Expand Up @@ -63,6 +64,8 @@ static class Application {
@MockBean
private Supplier<GraphQLContext> graphqlContext;

@MockBean
private RestrictedKeysProvider restrictedKeysProvider;
}

@Autowired(required=false)
Expand All @@ -85,6 +88,9 @@ static class Application {

@Autowired
private ObjectProvider<Supplier<GraphQLContext>> graphqlContext;

@Autowired
private ObjectProvider<RestrictedKeysProvider> restrictedKeysObjectProvider;

@Autowired
private GraphQLSchema graphQLSchema;
Expand All @@ -96,6 +102,9 @@ public void contextIsAutoConfigured() {

assertThat(graphQLSchemaBuilder).isNotNull()
.isInstanceOf(GraphQLJpaSchemaBuilder.class);

assertThat(GraphQLJpaSchemaBuilder.class.cast(graphQLSchemaBuilder)
.getRestrictedKeysProvider()).isEqualTo(restrictedKeysObjectProvider.getObject());

assertThat(executorContextFactory).isNotNull()
.isInstanceOf(GraphQLJpaExecutorContextFactory.class);
Expand Down
12 changes: 12 additions & 0 deletions graphql-jpa-query-schema/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,18 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.introproventures.graphql.jpa.query.schema;

import java.util.List;
import java.util.Optional;
import java.util.function.Function;

import com.introproventures.graphql.jpa.query.schema.impl.EntityIntrospector.EntityIntrospectionResult;

/**
* The RestrictedKeysProvider functional interface should provide a list of restricted keys in order to filter records
* at runtime based on user security context based on EntityIntrospection descriptor.
*
* The return argument uses Optional<List<Object>> return type:
* The non-empty list will restrict the query to provided keys
* The empty list will run the query unrestricted.
* The empty Optional will block running the query and return empty result.
*
*/
@FunctionalInterface
public interface RestrictedKeysProvider extends Function<EntityIntrospectionResult, Optional<List<Object>>> {

/**
* Applies this restricted keys provider function to the given argument of entityDescriptor.
*
* @param entityDescriptor the function argument
* @return the function result with optional list of keys
*/
@Override
Optional<List<Object>> apply(EntityIntrospectionResult entityDescriptor);

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.getSelectionField;
import static com.introproventures.graphql.jpa.query.support.GraphQLSupport.searchByFieldName;

import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -74,21 +74,32 @@ public PagedResult<Object> get(DataFetchingEnvironment environment) {
final PagedResult.Builder<Object> pagedResult = PagedResult.builder()
.withOffset(firstResult)
.withLimit(maxResults);
Optional<List<Object>> restrictedKeys = queryFactory.getRestrictedKeys(environment);

if (recordsSelection.isPresent()) {
List<Object> keys = Collections.emptyList();

if (pageArgument.isPresent() || enableDefaultMaxResults) {
keys = queryFactory.queryKeys(environment, firstResult, maxResults);
}

final List<Object> resultList = queryFactory.queryResultList(environment,
maxResults,
keys);
pagedResult.withSelect(resultList);
if (restrictedKeys.isPresent()) {
final List<Object> queryKeys = new ArrayList<>();

if (pageArgument.isPresent() || enableDefaultMaxResults) {
queryKeys.addAll(queryFactory.queryKeys(environment,
firstResult,
maxResults,
restrictedKeys.get()));
}
else {
queryKeys.addAll(restrictedKeys.get());
}

final List<Object> resultList = queryFactory.queryResultList(environment,
maxResults,
queryKeys);
pagedResult.withSelect(resultList);
}
}

if (totalSelection.isPresent() || pagesSelection.isPresent()) {
final Long total = queryFactory.queryTotalCount(environment);
final Long total = queryFactory.queryTotalCount(environment,
restrictedKeys);

pagedResult.withTotal(total);
}
Expand Down
Loading