44require_relative "composer/validate_interfaces"
55require_relative "composer/validate_type_resolvers"
66require_relative "composer/type_resolver_config"
7+ require_relative "composer/authorization"
78
89module GraphQL
910 module Stitching
1011 # Composer receives many individual `GraphQL::Schema` instances
1112 # representing various graph locations and merges them into one
1213 # combined Supergraph that is validated for integrity.
1314 class Composer
15+ include Authorization
16+
1417 # @api private
1518 NO_DEFAULT_VALUE = begin
1619 t = Class . new ( GraphQL ::Schema ::Object ) do
@@ -60,6 +63,7 @@ def initialize(
6063 @resolver_configs = { }
6164 @mapped_type_names = { }
6265 @visibility_profiles = Set . new ( visibility_profiles )
66+ @authorizations_by_type_and_field = { }
6367 @subgraph_directives_by_name_and_location = nil
6468 @subgraph_types_by_name_and_location = nil
6569 @schema_directives = nil
@@ -74,6 +78,7 @@ def perform(locations_input)
7478
7579 directives_to_omit = [
7680 GraphQL ::Stitching . stitch_directive ,
81+ GraphQL ::Stitching . authorization_directive ,
7782 Directives ::SupergraphKey . graphql_name ,
7883 Directives ::SupergraphResolver . graphql_name ,
7984 Directives ::SupergraphSource . graphql_name ,
@@ -169,6 +174,7 @@ def perform(locations_input)
169174 select_root_field_locations ( schema )
170175 expand_abstract_resolvers ( schema , schemas )
171176 apply_supergraph_directives ( schema , @resolver_map , @field_map )
177+ apply_authorization_directives ( schema , @authorizations_by_type_and_field )
172178
173179 if ( visibility_def = schema . directives [ GraphQL ::Stitching . visibility_directive ] )
174180 visibility_def . get_argument ( "profiles" ) . default_value ( @visibility_profiles . to_a . sort )
@@ -201,6 +207,10 @@ def prepare_locations_input(locations_input)
201207 @resolver_configs . merge! ( TypeResolverConfig . extract_directive_assignments ( schema , location , input [ :stitch ] ) )
202208 @resolver_configs . merge! ( TypeResolverConfig . extract_federation_entities ( schema , location ) )
203209
210+ if schema . directives [ GraphQL ::Stitching . authorization_directive ]
211+ SubgraphAuthorization . new ( schema ) . reverse_merge! ( @authorizations_by_type_and_field )
212+ end
213+
204214 schemas [ location . to_s ] = schema
205215 executables [ location . to_s ] = input [ :executable ] || schema
206216 end
@@ -750,6 +760,24 @@ def apply_supergraph_directives(schema, resolvers_by_type_name, locations_by_typ
750760
751761 schema_directives . each_value { |directive_class | schema . directive ( directive_class ) }
752762 end
763+
764+ def apply_authorization_directives ( schema , authorizations_by_type_and_field )
765+ return if authorizations_by_type_and_field . empty?
766+
767+ schema . types . each_value do |type |
768+ authorizations_by_field = authorizations_by_type_and_field [ type . graphql_name ]
769+ next if authorizations_by_field . nil? || !type . kind . fields?
770+
771+ type . fields . each_value do |field |
772+ scopes = authorizations_by_field [ field . graphql_name ]
773+ next if scopes . nil?
774+
775+ field . directive ( Directives ::Authorization , scopes : scopes )
776+ end
777+ end
778+
779+ schema . directive ( Directives ::Authorization )
780+ end
753781 end
754782 end
755783end
0 commit comments