If I have a GraphQL API looking like this:
type Query {
userById (id: ID): User
}
type User {
id: ID
name: String
secret: String
supervisor: Supervisor
}
type Supervisor {
id: ID
name: String
users: [User]
}
User X is logged in and triggers the legitimate query:
query {
userById (id: "X") {
name
secret
supervisor: {
name
}
}
}
He is authorized since he has access to his own User object.
But what if the user modifies the query to this:
query {
userById (id: "X") {
name
secret
supervisor: {
name
users {
secret
}
}
}
}
How can I secure users from fetching other users by traversing the graph. Specifically using Spring for GraphQL, https://spring.io/projects/spring-graphql. I also use Spring Security.
I managed to do what I want by configuring like this (simplified here - in reality I delegate the logic to a Spring bean implementing the DataFetcher interface which in turn uses @Service:s which handles security). This way the default PropertyDataFetcher is replaced by my own implementation, where security logic may be performed.
@Configuration
public class GraphQLConfig implements RuntimeWiringConfigurer {
@Autowired
private SupervisorRepository supervisorRepository;
@Override
public void configure(RuntimeWiring.Builder builder) {
GraphQLCodeRegistry codeRegistry = GraphQLCodeRegistry.newCodeRegistry()
.dataFetcher(
coordinates("User", "supervisor"),
(DataFetcher<Supervisor>) environment -> {
User user = environment.getSource();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// Do security stuff and find supervisor by the user entity
supervisorRepository.find...
}
).build();
builder.codeRegistry(codeRegistry);
}
}