@theguild/federation-composition
Version:
Open Source Composition library for Apollo Federation
63 lines (62 loc) • 3.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthOnContextRule = AuthOnContextRule;
const graphql_1 = require("graphql");
const helpers_js_1 = require("../../../subgraph/helpers.js");
const state_js_1 = require("../../../subgraph/state.js");
const auth_on_requires_rule_js_1 = require("./auth-on-requires-rule.js");
function AuthOnContextRule(context, supergraph) {
return {
ObjectTypeField(objectTypeState, fieldState) {
for (const { graphId, fromContext } of contextualArgs(fieldState)) {
const subgraphState = context.subgraphStates.get(graphId);
const selectionSet = (0, helpers_js_1.parseFields)(fromContext.selection);
if (!subgraphState || !selectionSet) {
continue;
}
const provisionedAccess = new auth_on_requires_rule_js_1.ProvisionedAccess(objectTypeState, fieldState);
for (const providerName of findContextProviders(subgraphState, fromContext.context)) {
const providerType = supergraph.objectTypes.get(providerName) ??
supergraph.interfaceTypes.get(providerName) ??
supergraph.unionTypes.get(providerName);
if (!providerType ||
!(0, auth_on_requires_rule_js_1.ensureAccessToSelectionSet)(supergraph, providerType, selectionSet, provisionedAccess)) {
continue;
}
context.reportError(createContextAccessRequirementError(context.graphIdToName(graphId), `${objectTypeState.name}.${fieldState.name}`, `${context.graphIdToName(graphId)}__${fromContext.context}`));
return;
}
}
},
};
}
function contextualArgs(fieldState) {
const args = [];
for (const arg of fieldState.args.values()) {
for (const [graphId, argInGraph] of arg.byGraph) {
if (argInGraph.fromContext) {
args.push({ graphId, fromContext: argInGraph.fromContext });
}
}
}
return args;
}
function findContextProviders(subgraphState, contextName) {
const providers = [];
for (const [typeName, typeState] of subgraphState.types) {
if ((typeState.kind === state_js_1.TypeKind.OBJECT ||
typeState.kind === state_js_1.TypeKind.INTERFACE ||
typeState.kind === state_js_1.TypeKind.UNION) &&
typeState.contexts.has(contextName)) {
providers.push(typeName);
}
}
return providers;
}
function createContextAccessRequirementError(graphName, fieldCoordinate, contextName) {
return new graphql_1.GraphQLError(`[${graphName}] Field "${fieldCoordinate}" does not specify necessary @authenticated, @requiresScopes and/or @policy auth requirements to access the transitive data in context ${contextName} from @fromContext selection set.`, {
extensions: {
code: "MISSING_TRANSITIVE_AUTH_REQUIREMENTS",
},
});
}