use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class GraphQLResponseProcessor method handleResponse.
/**
* Handle inbound websocket responses of GraphQL subscriptions and perform authentication, authorization
* and throttling. This identifies operation from the subscription responses using the unique message id parameter.
*
* @param msgSize Message size of graphQL subscription response payload
* @param msgText The GraphQL subscription response payload text
* @param inboundMessageContext InboundMessageContext
* @return InboundProcessorResponseDTO
*/
@Override
public InboundProcessorResponseDTO handleResponse(int msgSize, String msgText, InboundMessageContext inboundMessageContext) {
InboundProcessorResponseDTO responseDTO = InboundWebsocketProcessorUtil.authenticateToken(inboundMessageContext);
JSONObject graphQLMsg = new JSONObject(msgText);
if (!responseDTO.isError() && checkIfSubscribeMessageResponse(graphQLMsg)) {
if (graphQLMsg.has(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_ID) && graphQLMsg.getString(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_ID) != null) {
String operationId = graphQLMsg.getString(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_ID);
GraphQLOperationDTO graphQLOperationDTO = inboundMessageContext.getVerbInfoForGraphQLMsgId(graphQLMsg.getString(GraphQLConstants.SubscriptionConstants.PAYLOAD_FIELD_NAME_ID));
// validate scopes based on subscription payload when security is enabled
String authType = graphQLOperationDTO.getVerbInfoDTO().getAuthType();
if (!StringUtils.capitalize(APIConstants.AUTH_TYPE_NONE.toLowerCase()).equals(authType)) {
responseDTO = InboundWebsocketProcessorUtil.validateScopes(inboundMessageContext, graphQLOperationDTO.getOperation(), operationId);
}
if (!responseDTO.isError()) {
// throttle for matching resource
return InboundWebsocketProcessorUtil.doThrottleForGraphQL(msgSize, graphQLOperationDTO.getVerbInfoDTO(), inboundMessageContext, operationId);
}
} else {
responseDTO = InboundWebsocketProcessorUtil.getBadRequestFrameErrorDTO("Missing mandatory id field in the message");
}
}
return responseDTO;
}
use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method isAuthenticated.
/**
* Authenticate inbound websocket request handshake.
*
* @param inboundMessageContext InboundMessageContext
* @return whether authenticated or not
* @throws APIManagementException if an internal error occurs
* @throws APISecurityException if authentication fails
*/
public static boolean isAuthenticated(InboundMessageContext inboundMessageContext) throws APISecurityException, APIManagementException {
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(inboundMessageContext.getTenantDomain(), true);
APIKeyValidationInfoDTO info;
String authorizationHeader = inboundMessageContext.getRequestHeaders().get(HttpHeaders.AUTHORIZATION);
inboundMessageContext.getRequestHeaders().put(HttpHeaders.AUTHORIZATION, authorizationHeader);
String[] auth = authorizationHeader.split(StringUtils.SPACE);
List<String> keyManagerList = DataHolder.getInstance().getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid());
if (APIConstants.CONSUMER_KEY_SEGMENT.equals(auth[0])) {
String cacheKey;
boolean isJwtToken = false;
String apiKey = auth[1];
if (WebsocketUtil.isRemoveOAuthHeadersFromOutMessage()) {
inboundMessageContext.getRequestHeaders().remove(HttpHeaders.AUTHORIZATION);
}
// Initial guess of a JWT token using the presence of a DOT.
if (StringUtils.isNotEmpty(apiKey) && apiKey.contains(APIConstants.DOT)) {
try {
// Check if the header part is decoded
if (StringUtils.countMatches(apiKey, APIConstants.DOT) != 2) {
log.debug("Invalid JWT token. The expected token format is <header.payload.signature>");
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid JWT token");
}
inboundMessageContext.setSignedJWTInfo(getSignedJwtInfo(apiKey));
String keyManager = ServiceReferenceHolder.getInstance().getJwtValidationService().getKeyManagerNameIfJwtValidatorExist(inboundMessageContext.getSignedJWTInfo());
if (StringUtils.isNotEmpty(keyManager)) {
if (log.isDebugEnabled()) {
log.debug("KeyManager " + keyManager + "found for authenticate token " + GatewayUtils.getMaskedToken(apiKey));
}
if (keyManagerList.contains(APIConstants.KeyManager.API_LEVEL_ALL_KEY_MANAGERS) || keyManagerList.contains(keyManager)) {
if (log.isDebugEnabled()) {
log.debug("Elected KeyManager " + keyManager + "found in API level list " + String.join(",", keyManagerList));
}
isJwtToken = true;
} else {
if (log.isDebugEnabled()) {
log.debug("Elected KeyManager " + keyManager + " not found in API level list " + String.join(",", keyManagerList));
}
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid JWT token");
}
} else {
if (log.isDebugEnabled()) {
log.debug("KeyManager not found for accessToken " + GatewayUtils.getMaskedToken(apiKey));
}
}
} catch (ParseException e) {
log.debug("Not a JWT token. Failed to decode the token header.", e);
} catch (APIManagementException e) {
log.error("Error while checking validation of JWT", e);
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
}
}
// Find the authentication scheme based on the token type
if (isJwtToken) {
log.debug("The token was identified as a JWT token");
if (APIConstants.GRAPHQL_API.equals(inboundMessageContext.getElectedAPI().getApiType())) {
return InboundWebsocketProcessorUtil.authenticateGraphQLJWTToken(inboundMessageContext);
} else {
return InboundWebsocketProcessorUtil.authenticateWSJWTToken(inboundMessageContext);
}
} else {
log.debug("The token was identified as an OAuth token");
// If the key have already been validated
if (WebsocketUtil.isGatewayTokenCacheEnabled()) {
cacheKey = WebsocketUtil.getAccessTokenCacheKey(apiKey, inboundMessageContext.getApiContext(), inboundMessageContext.getMatchingResource());
info = WebsocketUtil.validateCache(apiKey, cacheKey);
if (info != null) {
inboundMessageContext.setKeyType(info.getType());
inboundMessageContext.setInfoDTO(info);
return info.isAuthorized();
}
}
info = getApiKeyDataForWSClient(apiKey, inboundMessageContext.getTenantDomain(), inboundMessageContext.getApiContext(), inboundMessageContext.getVersion(), keyManagerList);
if (info == null || !info.isAuthorized()) {
return false;
}
if (WebsocketUtil.isGatewayTokenCacheEnabled()) {
cacheKey = WebsocketUtil.getAccessTokenCacheKey(apiKey, inboundMessageContext.getApiContext(), inboundMessageContext.getMatchingResource());
WebsocketUtil.putCache(info, apiKey, cacheKey);
}
inboundMessageContext.setKeyType(info.getType());
inboundMessageContext.setToken(info.getEndUserToken());
inboundMessageContext.setInfoDTO(info);
return true;
}
} else {
return false;
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method publishGoogleAnalyticsData.
/**
* Publish Google Analytics data.
*
* @param inboundMessageContext InboundMessageContext
* @param remoteAddress Remote IP address
* @throws WebSocketApiException if an error occurs
*/
public static void publishGoogleAnalyticsData(InboundMessageContext inboundMessageContext, String remoteAddress) throws WebSocketApiException {
// publish Google Analytics data
GoogleAnalyticsData.DataBuilder gaData;
try {
gaData = new GoogleAnalyticsData.DataBuilder(null, null, null, null).setDocumentPath(inboundMessageContext.getFullRequestPath()).setDocumentHostName(DataPublisherUtil.getHostAddress()).setSessionControl("end").setCacheBuster(APIMgtGoogleAnalyticsUtils.getCacheBusterId()).setIPOverride(remoteAddress);
APIMgtGoogleAnalyticsUtils gaUtils = new APIMgtGoogleAnalyticsUtils();
gaUtils.init(inboundMessageContext.getTenantDomain());
gaUtils.publishGATrackingData(gaData, inboundMessageContext.getRequestHeaders().get(HttpHeaders.USER_AGENT), inboundMessageContext.getRequestHeaders().get(HttpHeaders.AUTHORIZATION));
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw new WebSocketApiException("Error while publishing google analytics data for API " + inboundMessageContext.getApiContext());
}
}
use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method validateAuthenticationContext.
/**
* Validates AuthenticationContext and set APIKeyValidationInfoDTO to InboundMessageContext.
*
* @param authenticationContext Validated AuthenticationContext
* @param inboundMessageContext InboundMessageContext
* @return true if authenticated
*/
public static boolean validateAuthenticationContext(AuthenticationContext authenticationContext, InboundMessageContext inboundMessageContext) {
if (authenticationContext == null || !authenticationContext.isAuthenticated()) {
return false;
}
// The information given by the AuthenticationContext is set to an APIKeyValidationInfoDTO object
// so to feed information analytics and throttle data publishing
APIKeyValidationInfoDTO info = new APIKeyValidationInfoDTO();
info.setAuthorized(authenticationContext.isAuthenticated());
info.setApplicationTier(authenticationContext.getApplicationTier());
info.setTier(authenticationContext.getTier());
info.setSubscriberTenantDomain(authenticationContext.getSubscriberTenantDomain());
info.setSubscriber(authenticationContext.getSubscriber());
info.setStopOnQuotaReach(authenticationContext.isStopOnQuotaReach());
info.setApiName(authenticationContext.getApiName());
info.setApplicationId(authenticationContext.getApplicationId());
info.setType(authenticationContext.getKeyType());
info.setApiPublisher(authenticationContext.getApiPublisher());
info.setApplicationName(authenticationContext.getApplicationName());
info.setConsumerKey(authenticationContext.getConsumerKey());
info.setEndUserName(authenticationContext.getUsername());
info.setApiTier(authenticationContext.getApiTier());
info.setGraphQLMaxDepth(authenticationContext.getGraphQLMaxDepth());
info.setGraphQLMaxComplexity(authenticationContext.getGraphQLMaxComplexity());
inboundMessageContext.setKeyType(info.getType());
inboundMessageContext.setInfoDTO(info);
inboundMessageContext.setAuthContext(authenticationContext);
inboundMessageContext.setInfoDTO(info);
return authenticationContext.isAuthenticated();
}
use of org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method doThrottleForGraphQL.
/**
* Checks if the request is throttled for GraphQL subscriptions.
*
* @param msgSize Websocket msg size
* @param verbInfoDTO VerbInfoDTO for invoking operation.
* @param inboundMessageContext InboundMessageContext
* @param operationId Operation ID
* @return InboundProcessorResponseDTO
*/
public static InboundProcessorResponseDTO doThrottleForGraphQL(int msgSize, VerbInfoDTO verbInfoDTO, InboundMessageContext inboundMessageContext, String operationId) {
GraphQLProcessorResponseDTO responseDTO = new GraphQLProcessorResponseDTO();
responseDTO.setId(operationId);
return InboundWebsocketProcessorUtil.doThrottle(msgSize, verbInfoDTO, inboundMessageContext, responseDTO);
}
Aggregations