use of org.wso2.carbon.apimgt.gateway.handlers.graphQL.analyzer.SubscriptionAnalyzer in project carbon-apimgt by wso2.
the class GraphQLRequestProcessor method handleRequest.
/**
* Handle inbound websocket requests for GraphQL subscriptions and perform authentication, authorization,
* payload validation, query depth and complexity analysis and throttling.
*
* @param msgSize Message size of graphQL subscription payload
* @param msgText The GraphQL subscription payload text
* @param inboundMessageContext InboundMessageContext
* @return InboundProcessorResponseDTO
*/
@Override
public InboundProcessorResponseDTO handleRequest(int msgSize, String msgText, InboundMessageContext inboundMessageContext) {
InboundProcessorResponseDTO responseDTO;
JSONObject graphQLMsg = new JSONObject(msgText);
responseDTO = InboundWebsocketProcessorUtil.authenticateToken(inboundMessageContext);
Parser parser = new Parser();
// for gql subscription operation payloads
if (!responseDTO.isError() && checkIfSubscribeMessage(graphQLMsg)) {
String operationId = graphQLMsg.getString(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_ID);
if (validatePayloadFields(graphQLMsg)) {
String graphQLSubscriptionPayload = ((JSONObject) graphQLMsg.get(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_PAYLOAD)).getString(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_QUERY);
Document document = parser.parseDocument(graphQLSubscriptionPayload);
// Extract the operation type and operations from the payload
OperationDefinition operation = getOperationFromPayload(document);
if (operation != null) {
if (checkIfValidSubscribeOperation(operation)) {
responseDTO = validateQueryPayload(inboundMessageContext, document, operationId);
if (!responseDTO.isError()) {
// subscription operation name
String subscriptionOperation = GraphQLProcessorUtil.getOperationList(operation, inboundMessageContext.getGraphQLSchemaDTO().getTypeDefinitionRegistry());
// extract verb info dto with throttle policy for matching verb
VerbInfoDTO verbInfoDTO = InboundWebsocketProcessorUtil.findMatchingVerb(subscriptionOperation, inboundMessageContext);
String authType = verbInfoDTO.getAuthType();
// validate scopes based on subscription payload when security is enabled
if (!StringUtils.capitalize(APIConstants.AUTH_TYPE_NONE.toLowerCase()).equals(authType)) {
responseDTO = InboundWebsocketProcessorUtil.validateScopes(inboundMessageContext, subscriptionOperation, operationId);
}
if (!responseDTO.isError()) {
SubscriptionAnalyzer subscriptionAnalyzer = new SubscriptionAnalyzer(inboundMessageContext.getGraphQLSchemaDTO().getGraphQLSchema());
// analyze query depth and complexity
responseDTO = validateQueryDepthAndComplexity(subscriptionAnalyzer, inboundMessageContext, graphQLSubscriptionPayload, operationId);
if (!responseDTO.isError()) {
// throttle for matching resource
responseDTO = InboundWebsocketProcessorUtil.doThrottleForGraphQL(msgSize, verbInfoDTO, inboundMessageContext, operationId);
// add verb info dto for the successful invoking subscription operation request
inboundMessageContext.addVerbInfoForGraphQLMsgId(graphQLMsg.getString(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_ID), new GraphQLOperationDTO(verbInfoDTO, subscriptionOperation));
}
}
}
} else {
responseDTO = InboundWebsocketProcessorUtil.getBadRequestGraphQLFrameErrorDTO("Invalid operation. Only allowed Subscription type operations", operationId);
}
} else {
responseDTO = InboundWebsocketProcessorUtil.getBadRequestGraphQLFrameErrorDTO("Operation definition cannot be empty", operationId);
}
} else {
responseDTO = InboundWebsocketProcessorUtil.getBadRequestGraphQLFrameErrorDTO("Invalid operation payload", operationId);
}
}
return responseDTO;
}
use of org.wso2.carbon.apimgt.gateway.handlers.graphQL.analyzer.SubscriptionAnalyzer in project carbon-apimgt by wso2.
the class GraphQLRequestProcessor method validateQueryComplexity.
/**
* Validate query complexity of graphql subscription payload.
*
* @param subscriptionAnalyzer Query complexity and depth analyzer for subscription operations
* @param inboundMessageContext InboundMessageContext
* @param payload GraphQL payload
* @param operationId Graphql message id
* @return GraphQLProcessorResponseDTO
*/
private GraphQLProcessorResponseDTO validateQueryComplexity(SubscriptionAnalyzer subscriptionAnalyzer, InboundMessageContext inboundMessageContext, String payload, String operationId) {
GraphQLProcessorResponseDTO responseDTO = new GraphQLProcessorResponseDTO();
responseDTO.setId(operationId);
try {
QueryAnalyzerResponseDTO queryAnalyzerResponseDTO = subscriptionAnalyzer.analyseSubscriptionQueryComplexity(payload, inboundMessageContext.getInfoDTO().getGraphQLMaxComplexity());
if (!queryAnalyzerResponseDTO.isSuccess() && !queryAnalyzerResponseDTO.getErrorList().isEmpty()) {
List<String> errorList = queryAnalyzerResponseDTO.getErrorList();
log.error("Query complexity validation failed for: " + payload + " errors: " + errorList.toString());
responseDTO.setError(true);
responseDTO.setErrorCode(WebSocketApiConstants.FrameErrorConstants.GRAPHQL_QUERY_TOO_COMPLEX);
responseDTO.setErrorMessage(WebSocketApiConstants.FrameErrorConstants.GRAPHQL_QUERY_TOO_COMPLEX_MESSAGE + " : " + queryAnalyzerResponseDTO.getErrorList().toString());
return responseDTO;
}
} catch (APIManagementException e) {
log.error("Error while validating query complexity for: " + payload, e);
responseDTO.setError(true);
responseDTO.setErrorMessage(e.getMessage());
responseDTO.setErrorCode(WebSocketApiConstants.FrameErrorConstants.INTERNAL_SERVER_ERROR);
}
return responseDTO;
}
use of org.wso2.carbon.apimgt.gateway.handlers.graphQL.analyzer.SubscriptionAnalyzer in project carbon-apimgt by wso2.
the class GraphQLRequestProcessor method validateQueryDepth.
/**
* Validate query depth of graphql subscription payload.
*
* @param subscriptionAnalyzer Query complexity and depth analyzer for subscription operations
* @param inboundMessageContext InboundMessageContext
* @param payload GraphQL payload
* @param operationId GraphQL message Id
* @return GraphQLProcessorResponseDTO
*/
private GraphQLProcessorResponseDTO validateQueryDepth(SubscriptionAnalyzer subscriptionAnalyzer, InboundMessageContext inboundMessageContext, String payload, String operationId) {
GraphQLProcessorResponseDTO responseDTO = new GraphQLProcessorResponseDTO();
responseDTO.setId(operationId);
QueryAnalyzerResponseDTO queryAnalyzerResponseDTO = subscriptionAnalyzer.analyseSubscriptionQueryDepth(inboundMessageContext.getInfoDTO().getGraphQLMaxDepth(), payload);
if (!queryAnalyzerResponseDTO.isSuccess() && !queryAnalyzerResponseDTO.getErrorList().isEmpty()) {
List<String> errorList = queryAnalyzerResponseDTO.getErrorList();
log.error("Query depth validation failed for: " + payload + " errors: " + errorList.toString());
responseDTO.setError(true);
responseDTO.setErrorCode(WebSocketApiConstants.FrameErrorConstants.GRAPHQL_QUERY_TOO_DEEP);
responseDTO.setErrorMessage(WebSocketApiConstants.FrameErrorConstants.GRAPHQL_QUERY_TOO_DEEP_MESSAGE + " : " + queryAnalyzerResponseDTO.getErrorList().toString());
return responseDTO;
}
return responseDTO;
}
Aggregations