Search in sources :

Example 1 with SubscriptionAnalyzer

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;
}
Also used : GraphQLOperationDTO(org.wso2.carbon.apimgt.gateway.dto.GraphQLOperationDTO) JSONObject(org.json.JSONObject) VerbInfoDTO(org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO) InboundProcessorResponseDTO(org.wso2.carbon.apimgt.gateway.inbound.websocket.InboundProcessorResponseDTO) Document(graphql.language.Document) OperationDefinition(graphql.language.OperationDefinition) SubscriptionAnalyzer(org.wso2.carbon.apimgt.gateway.handlers.graphQL.analyzer.SubscriptionAnalyzer) Parser(graphql.parser.Parser)

Example 2 with SubscriptionAnalyzer

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;
}
Also used : GraphQLProcessorResponseDTO(org.wso2.carbon.apimgt.gateway.inbound.websocket.GraphQLProcessorResponseDTO) APIManagementException(org.wso2.carbon.apimgt.api.APIManagementException) QueryAnalyzerResponseDTO(org.wso2.carbon.apimgt.common.gateway.dto.QueryAnalyzerResponseDTO)

Example 3 with SubscriptionAnalyzer

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;
}
Also used : GraphQLProcessorResponseDTO(org.wso2.carbon.apimgt.gateway.inbound.websocket.GraphQLProcessorResponseDTO) QueryAnalyzerResponseDTO(org.wso2.carbon.apimgt.common.gateway.dto.QueryAnalyzerResponseDTO)

Aggregations

QueryAnalyzerResponseDTO (org.wso2.carbon.apimgt.common.gateway.dto.QueryAnalyzerResponseDTO)2 GraphQLProcessorResponseDTO (org.wso2.carbon.apimgt.gateway.inbound.websocket.GraphQLProcessorResponseDTO)2 Document (graphql.language.Document)1 OperationDefinition (graphql.language.OperationDefinition)1 Parser (graphql.parser.Parser)1 JSONObject (org.json.JSONObject)1 APIManagementException (org.wso2.carbon.apimgt.api.APIManagementException)1 GraphQLOperationDTO (org.wso2.carbon.apimgt.gateway.dto.GraphQLOperationDTO)1 SubscriptionAnalyzer (org.wso2.carbon.apimgt.gateway.handlers.graphQL.analyzer.SubscriptionAnalyzer)1 InboundProcessorResponseDTO (org.wso2.carbon.apimgt.gateway.inbound.websocket.InboundProcessorResponseDTO)1 VerbInfoDTO (org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO)1