use of org.wso2.carbon.apimgt.rest.api.util.MethodStats in project carbon-apimgt by wso2.
the class OAuthAuthenticationInterceptor method handleMessage.
@Override
@MethodStats
public void handleMessage(Message inMessage) {
// by-passes the interceptor if user calls an anonymous api
if (RestApiUtil.checkIfAnonymousAPI(inMessage)) {
return;
}
HashMap<String, Object> authContext = JWTAuthenticationUtils.addToJWTAuthenticationContext(inMessage);
RestAPIAuthenticator authenticator = RestAPIAuthenticationManager.getAuthenticator(authContext);
if (authenticator != null) {
try {
String authenticationType = authenticator.getAuthenticationType();
inMessage.put(RestApiConstants.REQUEST_AUTHENTICATION_SCHEME, authenticator.getAuthenticationType());
String basePath = (String) inMessage.get(RestApiConstants.BASE_PATH);
String version = (String) inMessage.get(RestApiConstants.API_VERSION);
authContext.put(RestApiConstants.URI_TEMPLATES, RestApiUtil.getURITemplatesForBasePath(basePath + version));
authContext.put(RestApiConstants.ORG_ID, RestApiUtil.resolveOrganization(inMessage));
if (authenticator.authenticate(authContext)) {
inMessage = JWTAuthenticationUtils.addToMessageContext(inMessage, authContext);
if (logger.isDebugEnabled()) {
logger.debug("Request has been Authenticated , authentication type : " + authenticationType);
}
} else {
logger.error("Failed to Authenticate , authentication type : " + authenticationType);
throw new AuthenticationException("Unauthenticated request");
}
} catch (APIManagementException e) {
logger.error("Authentication Failure " + e.getMessage());
return;
}
}
// Following logic will be moved to separate class in near future
if (authenticator == null) {
String accessToken = RestApiUtil.extractOAuthAccessTokenFromMessage(inMessage, RestApiConstants.REGEX_BEARER_PATTERN, RestApiConstants.AUTH_HEADER_NAME);
// add masked token to the Message
inMessage.put(RestApiConstants.MASKED_TOKEN, APIUtil.getMaskedToken(accessToken));
if (accessToken == null) {
return;
}
if (accessToken.contains(RestApiConstants.DOT)) {
inMessage.put(RestApiConstants.REQUEST_AUTHENTICATION_SCHEME, RestApiConstants.JWT_AUTHENTICATION);
} else {
inMessage.put(RestApiConstants.REQUEST_AUTHENTICATION_SCHEME, RestApiConstants.OPAQUE_AUTHENTICATION);
}
try {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Authenticating request with : " + inMessage.get(RestApiConstants.REQUEST_AUTHENTICATION_SCHEME)) + "Authentication");
}
AbstractOAuthAuthenticator abstractOAuthAuthenticator = authenticatorMap.get(inMessage.get(RestApiConstants.REQUEST_AUTHENTICATION_SCHEME));
logger.debug("Selected Authenticator for the token validation " + abstractOAuthAuthenticator);
if (abstractOAuthAuthenticator.authenticate(inMessage)) {
if (logger.isDebugEnabled()) {
logger.debug("User logged into Web app using OAuth Authentication");
}
} else {
throw new AuthenticationException("Unauthenticated request");
}
} catch (APIManagementException e) {
logger.error("Error while authenticating incoming request to API Manager REST API", e);
}
}
}
use of org.wso2.carbon.apimgt.rest.api.util.MethodStats in project carbon-apimgt by wso2.
the class BasicAuthAuthenticator method authenticate.
/**
* Authenticates the given request to see if an API consumer is allowed to access
* a particular API or not.
*
* @param synCtx The message to be authenticated
* @return an AuthenticationResponse object which contains the authentication status
*/
@MethodStats
public AuthenticationResponse authenticate(MessageContext synCtx) {
if (log.isDebugEnabled()) {
log.info("Basic Authentication initialized");
}
openAPI = (OpenAPI) synCtx.getProperty(APIMgtGatewayConstants.OPEN_API_OBJECT);
if (openAPI == null && !APIConstants.GRAPHQL_API.equals(synCtx.getProperty(APIConstants.API_TYPE))) {
log.error("OpenAPI definition is missing in the gateway. Basic authentication cannot be performed.");
return new AuthenticationResponse(false, isMandatory, true, APISecurityConstants.API_AUTH_MISSING_OPEN_API_DEF, "Basic authentication cannot be performed.");
}
// Extract basic authorization header while removing it from the authorization header
String basicAuthHeader = extractBasicAuthHeader(synCtx);
String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
String httpMethod = (String) ((Axis2MessageContext) synCtx).getAxis2MessageContext().getProperty(Constants.Configuration.HTTP_METHOD);
String matchingResource = (String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE);
// Check for resource level authentication
String authenticationScheme;
List<VerbInfoDTO> verbInfoList;
if (APIConstants.GRAPHQL_API.equals(synCtx.getProperty(APIConstants.API_TYPE))) {
HashMap<String, Boolean> operationAuthSchemeMappingList = (HashMap<String, Boolean>) synCtx.getProperty(APIConstants.OPERATION_AUTH_SCHEME_MAPPING);
HashMap<String, String> operationThrottlingMappingList = (HashMap<String, String>) synCtx.getProperty(APIConstants.OPERATION_THROTTLING_MAPPING);
String[] operationList = matchingResource.split(",");
verbInfoList = new ArrayList<>(1);
authenticationScheme = APIConstants.AUTH_NO_AUTHENTICATION;
for (String operation : operationList) {
boolean operationAuthSchemeEnabled = operationAuthSchemeMappingList.get(operation);
VerbInfoDTO verbInfoDTO = new VerbInfoDTO();
if (operationAuthSchemeEnabled) {
verbInfoDTO.setAuthType(APIConstants.AUTH_APPLICATION_OR_USER_LEVEL_TOKEN);
authenticationScheme = APIConstants.AUTH_APPLICATION_OR_USER_LEVEL_TOKEN;
} else {
verbInfoDTO.setAuthType(APIConstants.AUTH_NO_AUTHENTICATION);
}
verbInfoDTO.setThrottling(operationThrottlingMappingList.get(operation));
verbInfoDTO.setRequestKey(apiContext + "/" + apiVersion + operation + ":" + httpMethod);
verbInfoList.add(verbInfoDTO);
}
} else {
authenticationScheme = OpenAPIUtils.getResourceAuthenticationScheme(openAPI, synCtx);
verbInfoList = new ArrayList<>(1);
VerbInfoDTO verbInfoDTO = new VerbInfoDTO();
verbInfoDTO.setAuthType(authenticationScheme);
verbInfoDTO.setThrottling(OpenAPIUtils.getResourceThrottlingTier(openAPI, synCtx));
verbInfoDTO.setRequestKey(apiContext + "/" + apiVersion + matchingResource + ":" + httpMethod);
verbInfoList.add(verbInfoDTO);
}
String[] credentials;
try {
credentials = extractBasicAuthCredentials(basicAuthHeader);
} catch (APISecurityException ex) {
return new AuthenticationResponse(false, isMandatory, true, ex.getErrorCode(), ex.getMessage());
}
String username = getEndUserName(credentials[0]);
String password = credentials[1];
// If end user tenant domain does not match the API publisher's tenant domain, return error
if (!MultitenantUtils.getTenantDomain(username).equals(synCtx.getProperty(PUBLISHER_TENANT_DOMAIN))) {
log.error("Basic Authentication failure: tenant domain mismatch for user :" + username);
return new AuthenticationResponse(false, isMandatory, true, APISecurityConstants.API_AUTH_FORBIDDEN, APISecurityConstants.API_AUTH_FORBIDDEN_MESSAGE);
}
BasicAuthValidationInfoDTO basicAuthValidationInfoObj;
try {
if (basicAuthCredentialValidator == null) {
basicAuthCredentialValidator = new BasicAuthCredentialValidator();
}
basicAuthValidationInfoObj = basicAuthCredentialValidator.validate(username, password);
} catch (APISecurityException ex) {
return new AuthenticationResponse(false, isMandatory, true, ex.getErrorCode(), ex.getMessage());
}
if (!basicAuthValidationInfoObj.isAuthenticated()) {
log.error("Basic Authentication failure: Username and Password mismatch");
return new AuthenticationResponse(false, isMandatory, true, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
} else {
// username password matches
if (log.isDebugEnabled()) {
log.debug("Basic Authentication: Username and Password authenticated");
}
// scope validation
boolean scopesValid = false;
try {
scopesValid = basicAuthCredentialValidator.validateScopes(username, openAPI, synCtx, basicAuthValidationInfoObj);
} catch (APISecurityException ex) {
return new AuthenticationResponse(false, isMandatory, true, ex.getErrorCode(), ex.getMessage());
}
String domainQualifiedUserName = basicAuthValidationInfoObj.getDomainQualifiedUsername();
if (scopesValid) {
if (APISecurityUtils.getAuthenticationContext(synCtx) == null) {
// Create a dummy AuthenticationContext object with hard coded values for
// Tier and KeyType. This is because we cannot determine the Tier nor Key
// Type without subscription information..
AuthenticationContext authContext = new AuthenticationContext();
authContext.setAuthenticated(true);
authContext.setTier(APIConstants.UNAUTHENTICATED_TIER);
authContext.setStopOnQuotaReach(// Since we don't have details on unauthenticated tier we setting stop on quota reach true
true);
synCtx.setProperty(APIConstants.VERB_INFO_DTO, verbInfoList);
// In basic authentication scenario, we will use the username for throttling.
authContext.setApiKey(domainQualifiedUserName);
authContext.setKeyType(APIConstants.API_KEY_TYPE_PRODUCTION);
authContext.setUsername(domainQualifiedUserName);
authContext.setCallerToken(null);
authContext.setApplicationName(APIConstants.BASIC_AUTH_APPLICATION_NAME);
// Set username as application ID in basic auth scenario
authContext.setApplicationId(domainQualifiedUserName);
// Set username as application ID in basic auth scenario
authContext.setApplicationUUID(domainQualifiedUserName);
// Set application owner in basic auth scenario
authContext.setSubscriber(APIConstants.BASIC_AUTH_APPLICATION_OWNER);
authContext.setConsumerKey(null);
authContext.setApiTier(apiLevelPolicy);
APISecurityUtils.setAuthenticationContext(synCtx, authContext, null);
}
log.debug("Basic Authentication: Scope validation passed");
return new AuthenticationResponse(true, isMandatory, false, 0, null);
}
return new AuthenticationResponse(false, isMandatory, true, APISecurityConstants.INVALID_SCOPE, "Scope validation failed");
}
}
use of org.wso2.carbon.apimgt.rest.api.util.MethodStats in project carbon-apimgt by wso2.
the class JWTValidator method authenticateForWebSocket.
/**
* Authenticates the given WebSocket handshake request with a JWT token to see if an API consumer is allowed to
* access a particular API or not.
*
* @param signedJWTInfo The JWT token sent with the API request
* @param apiContext The context of the invoked API
* @param apiVersion The version of the invoked API
* @param matchingResource template of matching api resource
* @return an AuthenticationContext object which contains the authentication information
* @throws APISecurityException in case of authentication failure
*/
@MethodStats
public AuthenticationContext authenticateForWebSocket(SignedJWTInfo signedJWTInfo, String apiContext, String apiVersion, String matchingResource) throws APISecurityException {
String tokenSignature = signedJWTInfo.getSignedJWT().getSignature().toString();
JWTClaimsSet jwtClaimsSet = signedJWTInfo.getJwtClaimsSet();
String jti = getJWTTokenIdentifier(signedJWTInfo);
JWTValidationInfo jwtValidationInfo = validateTokenForWS(signedJWTInfo, tokenSignature, jti);
if (jwtValidationInfo != null && jwtValidationInfo.isValid()) {
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = validateSubscriptionsForWS(jwtValidationInfo, apiContext, apiVersion);
if (apiKeyValidationInfoDTO.isAuthorized()) {
validateScopes(apiContext, apiVersion, matchingResource, WebSocketApiConstants.WEBSOCKET_DUMMY_HTTP_METHOD_NAME, jwtValidationInfo, signedJWTInfo);
log.debug("JWT authentication successful. user: " + apiKeyValidationInfoDTO.getEndUserName());
String endUserToken = generateBackendJWTForWS(jwtValidationInfo, apiKeyValidationInfoDTO, apiContext, apiVersion, tokenSignature);
return generateAuthenticationContextForWS(jti, jwtValidationInfo, apiKeyValidationInfoDTO, endUserToken, apiVersion);
} else {
String message = "User is NOT authorized to access the Resource. API Subscription validation failed.";
log.debug(message);
throw new APISecurityException(apiKeyValidationInfoDTO.getValidationStatus(), message);
}
} else if (!jwtValidationInfo.isValid()) {
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid JWT token");
}
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
}
use of org.wso2.carbon.apimgt.rest.api.util.MethodStats in project carbon-apimgt by wso2.
the class ThrottleHandler method doThrottle.
/**
* Do Throttle method will initialize throttle flow.
*
* @param messageContext message context object which contains message details.
* @return return true if message flow need to continue(message not throttled) and pass requests to next
* handler in chain. Else return false to notify throttled message.
*/
@MethodStats
private boolean doThrottle(MessageContext messageContext) {
org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) messageContext).getAxis2MessageContext();
ConfigurationContext cc = axis2MC.getConfigurationContext();
AuthenticationContext authenticationContext = APISecurityUtils.getAuthenticationContext(messageContext);
if (authenticationContext != null && authenticationContext.getSpikeArrestLimit() > 0) {
Timer timer = getTimer(MetricManager.name(APIConstants.METRICS_PREFIX, this.getClass().getSimpleName(), INIT_SPIKE_ARREST));
Timer.Context context = timer.start();
initThrottleForSubscriptionLevelSpikeArrest(messageContext, authenticationContext);
context.stop();
}
boolean isThrottled = false;
if (!messageContext.isResponse()) {
// org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) messageContext).
// getAxis2MessageContext();
// ConfigurationContext cc = axis2MC.getConfigurationContext();
Timer timer = getTimer(MetricManager.name(APIConstants.METRICS_PREFIX, this.getClass().getSimpleName(), CEP_THROTTLE));
Timer.Context context = timer.start();
isThrottled = doRoleBasedAccessThrottlingWithCEP(messageContext, cc, authenticationContext);
context.stop();
}
if (isThrottled) {
Timer timer = getTimer(MetricManager.name(APIConstants.METRICS_PREFIX, this.getClass().getSimpleName(), HANDLE_THROTTLE_OUT));
Timer.Context context = timer.start();
handleThrottleOut(messageContext);
context.stop();
return false;
}
return true;
}
use of org.wso2.carbon.apimgt.rest.api.util.MethodStats in project carbon-apimgt by wso2.
the class APIAuthenticationHandler method handleRequest.
@MethodStats
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "EXS_EXCEPTION_SOFTENING_RETURN_FALSE", justification = "Error is sent through payload")
public boolean handleRequest(MessageContext messageContext) {
TracingSpan keySpan = null;
if (Util.tracingEnabled()) {
TracingSpan responseLatencySpan = (TracingSpan) messageContext.getProperty(APIMgtGatewayConstants.RESOURCE_SPAN);
TracingTracer tracer = Util.getGlobalTracer();
keySpan = Util.startSpan(APIMgtGatewayConstants.KEY_VALIDATION, responseLatencySpan, tracer);
messageContext.setProperty(APIMgtGatewayConstants.KEY_VALIDATION, keySpan);
org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) messageContext).getAxis2MessageContext();
axis2MC.setProperty(APIMgtGatewayConstants.KEY_VALIDATION, keySpan);
}
Timer.Context context = startMetricTimer();
long startTime = System.nanoTime();
long endTime;
long difference;
if (Utils.isGraphQLSubscriptionRequest(messageContext)) {
if (log.isDebugEnabled()) {
log.debug("Skipping GraphQL subscription handshake request.");
}
return true;
}
try {
if (isAnalyticsEnabled()) {
long currentTime = System.currentTimeMillis();
messageContext.setProperty("api.ut.requestTime", Long.toString(currentTime));
}
messageContext.setProperty(APIMgtGatewayConstants.API_TYPE, apiType);
if (ExtensionListenerUtil.preProcessRequest(messageContext, type)) {
if (!isAuthenticatorsInitialized) {
initializeAuthenticators();
}
if (!isOauthParamsInitialized) {
initOAuthParams();
}
String authenticationScheme = getAPIKeyValidator().getResourceAuthenticationScheme(messageContext);
if (APIConstants.AUTH_NO_AUTHENTICATION.equals(authenticationScheme)) {
if (log.isDebugEnabled()) {
log.debug("Found Authentication Scheme: ".concat(authenticationScheme));
}
handleNoAuthentication(messageContext);
return true;
}
try {
if (isAuthenticate(messageContext)) {
setAPIParametersToMessageContext(messageContext);
return ExtensionListenerUtil.postProcessRequest(messageContext, type);
}
} catch (APIManagementException e) {
if (log.isDebugEnabled()) {
log.debug("Authentication of message context failed", e);
}
}
}
} catch (APISecurityException e) {
if (Util.tracingEnabled() && keySpan != null) {
Util.setTag(keySpan, APIMgtGatewayConstants.ERROR, APIMgtGatewayConstants.KEY_SPAN_ERROR);
}
if (log.isDebugEnabled()) {
// We do the calculations only if the debug logs are enabled. Otherwise this would be an overhead
// to all the gateway calls that is happening.
endTime = System.nanoTime();
difference = (endTime - startTime) / 1000000;
String messageDetails = logMessageDetails(messageContext);
log.debug("Call to Key Manager : " + messageDetails + ", elapsedTimeInMilliseconds=" + difference / 1000000);
}
String errorMessage = APISecurityConstants.getAuthenticationFailureMessage(e.getErrorCode());
if (APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE.equals(errorMessage)) {
log.error("API authentication failure due to " + APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE, e);
} else {
// We do not need to log known authentication failures as errors since these are not product errors.
log.warn("API authentication failure due to " + errorMessage);
if (log.isDebugEnabled()) {
log.debug("API authentication failed with error " + e.getErrorCode(), e);
}
}
handleAuthFailure(messageContext, e);
} finally {
if (Util.tracingEnabled()) {
Util.finishSpan(keySpan);
}
messageContext.setProperty(APIMgtGatewayConstants.SECURITY_LATENCY, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
stopMetricTimer(context);
}
return false;
}
Aggregations