use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext 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.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method authenticateWSJWTToken.
/**
* Authenticates JWT token in incoming Websocket handshake requests.
*
* @param inboundMessageContext InboundMessageContext
* @return true if authenticated
* @throws APIManagementException if an internal error occurs
* @throws APISecurityException if authentication fails
*/
public static boolean authenticateWSJWTToken(InboundMessageContext inboundMessageContext) throws APIManagementException, APISecurityException {
AuthenticationContext authenticationContext;
JWTValidator jwtValidator = new JWTValidator(new APIKeyValidator(), inboundMessageContext.getTenantDomain());
authenticationContext = jwtValidator.authenticateForWebSocket(inboundMessageContext.getSignedJWTInfo(), inboundMessageContext.getApiContext(), inboundMessageContext.getVersion(), inboundMessageContext.getMatchingResource());
return validateAuthenticationContext(authenticationContext, inboundMessageContext);
}
use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method authenticateGraphQLJWTToken.
/**
* Authenticates JWT token in incoming GraphQL subscription requests.
*
* @param inboundMessageContext InboundMessageContext
* @return true if authenticated
* @throws APIManagementException if an internal error occurs
* @throws APISecurityException if authentication fails
*/
public static boolean authenticateGraphQLJWTToken(InboundMessageContext inboundMessageContext) throws APIManagementException, APISecurityException {
AuthenticationContext authenticationContext;
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(inboundMessageContext.getTenantDomain(), true);
JWTValidator jwtValidator = new JWTValidator(new APIKeyValidator(), inboundMessageContext.getTenantDomain());
authenticationContext = jwtValidator.authenticateForGraphQLSubscription(inboundMessageContext.getSignedJWTInfo(), inboundMessageContext.getApiContext(), inboundMessageContext.getVersion());
return validateAuthenticationContext(authenticationContext, inboundMessageContext);
}
use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method authorizeGraphQLSubscriptionEvents.
/**
* Validate scopes of JWT token for incoming GraphQL subscription messages.
*
* @param matchingResource Invoking GraphQL subscription operation
* @param inboundMessageContext InboundMessageContext
* @return true if authorized
* @throws APIManagementException if an internal error occurs
* @throws APISecurityException if authorization fails
*/
public static boolean authorizeGraphQLSubscriptionEvents(String matchingResource, InboundMessageContext inboundMessageContext) throws APIManagementException, APISecurityException {
JWTValidator jwtValidator = new JWTValidator(new APIKeyValidator(), inboundMessageContext.getTenantDomain());
jwtValidator.validateScopesForGraphQLSubscriptions(inboundMessageContext.getApiContext(), inboundMessageContext.getVersion(), matchingResource, inboundMessageContext.getSignedJWTInfo(), inboundMessageContext.getAuthContext());
return true;
}
use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method doThrottle.
/**
* Checks if the request is throttled.
*
* @param msgSize Websocket msg size
* @param verbInfoDTO VerbInfoDTO for invoking operation. Pass null for websocket API throttling.
* @param inboundMessageContext InboundMessageContext
* @return false if throttled
*/
public static InboundProcessorResponseDTO doThrottle(int msgSize, VerbInfoDTO verbInfoDTO, InboundMessageContext inboundMessageContext, InboundProcessorResponseDTO responseDTO) {
APIKeyValidationInfoDTO infoDTO = inboundMessageContext.getInfoDTO();
String applicationLevelTier = infoDTO.getApplicationTier();
String apiLevelTier = infoDTO.getApiTier() == null && verbInfoDTO == null ? APIConstants.UNLIMITED_TIER : infoDTO.getApiTier();
String subscriptionLevelTier = infoDTO.getTier();
String resourceLevelTier;
String authorizedUser;
if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equalsIgnoreCase(infoDTO.getSubscriberTenantDomain())) {
authorizedUser = infoDTO.getSubscriber() + "@" + infoDTO.getSubscriberTenantDomain();
} else {
authorizedUser = infoDTO.getSubscriber();
}
String apiName = infoDTO.getApiName();
String apiVersion = inboundMessageContext.getVersion();
String appTenant = infoDTO.getSubscriberTenantDomain();
String apiTenant = inboundMessageContext.getTenantDomain();
String appId = infoDTO.getApplicationId();
String applicationLevelThrottleKey = appId + ":" + authorizedUser;
String apiLevelThrottleKey = inboundMessageContext.getApiContext() + ":" + apiVersion;
String resourceLevelThrottleKey;
// If API level throttle policy is present then it will apply and no resource level policy will apply for it
if (StringUtils.isNotEmpty(apiLevelTier) && verbInfoDTO == null) {
resourceLevelThrottleKey = apiLevelThrottleKey;
resourceLevelTier = apiLevelTier;
} else {
resourceLevelThrottleKey = verbInfoDTO.getRequestKey();
resourceLevelTier = verbInfoDTO.getThrottling();
}
String subscriptionLevelThrottleKey = appId + ":" + inboundMessageContext.getApiContext() + ":" + apiVersion;
String messageId = UIDGenerator.generateURNString();
String remoteIP = inboundMessageContext.getUserIP();
if (log.isDebugEnabled()) {
log.debug("Remote IP address : " + remoteIP);
}
if (remoteIP.indexOf(":") > 0) {
remoteIP = remoteIP.substring(1, remoteIP.indexOf(":"));
}
JSONObject jsonObMap = new JSONObject();
Utils.setRemoteIp(jsonObMap, remoteIP);
jsonObMap.put(APIThrottleConstants.MESSAGE_SIZE, msgSize);
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(inboundMessageContext.getTenantDomain(), true);
boolean isThrottled = WebsocketUtil.isThrottled(resourceLevelThrottleKey, subscriptionLevelThrottleKey, applicationLevelThrottleKey);
if (isThrottled) {
responseDTO.setError(true);
responseDTO.setErrorCode(WebSocketApiConstants.FrameErrorConstants.THROTTLED_OUT_ERROR);
responseDTO.setErrorMessage(WebSocketApiConstants.FrameErrorConstants.THROTTLED_OUT_ERROR_MESSAGE);
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
Object[] objects = new Object[] { messageId, applicationLevelThrottleKey, applicationLevelTier, apiLevelThrottleKey, apiLevelTier, subscriptionLevelThrottleKey, subscriptionLevelTier, resourceLevelThrottleKey, resourceLevelTier, authorizedUser, inboundMessageContext.getApiContext(), apiVersion, appTenant, apiTenant, appId, apiName, jsonObMap.toString() };
org.wso2.carbon.databridge.commons.Event event = new org.wso2.carbon.databridge.commons.Event("org.wso2.throttle.request.stream:1.0.0", System.currentTimeMillis(), null, null, objects);
if (ServiceReferenceHolder.getInstance().getThrottleDataPublisher() == null) {
log.error("Cannot publish events to traffic manager because ThrottleDataPublisher " + "has not been initialised");
}
ServiceReferenceHolder.getInstance().getThrottleDataPublisher().getDataPublisher().tryPublish(event);
return responseDTO;
}
Aggregations