use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.
the class APIKeyValidator method findMatchingVerb.
public List<VerbInfoDTO> findMatchingVerb(MessageContext synCtx) throws ResourceNotFoundException, APISecurityException {
List<VerbInfoDTO> verbInfoList = new ArrayList<>();
String resourceCacheKey;
String httpMethod = (String) ((Axis2MessageContext) synCtx).getAxis2MessageContext().getProperty(Constants.Configuration.HTTP_METHOD);
String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
String fullRequestPath = (String) synCtx.getProperty(RESTConstants.REST_FULL_REQUEST_PATH);
String electedResource = (String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE);
ArrayList<String> resourceArray = null;
if (electedResource != null) {
if (APIConstants.GRAPHQL_API.equalsIgnoreCase((String) synCtx.getProperty(APIConstants.API_TYPE))) {
resourceArray = new ArrayList<>(Arrays.asList(electedResource.split(",")));
} else {
resourceArray = new ArrayList<>(Arrays.asList(electedResource));
}
}
String requestPath = getRequestPath(synCtx, apiContext, apiVersion, fullRequestPath);
if ("".equals(requestPath)) {
requestPath = "/";
}
if (log.isDebugEnabled()) {
log.debug("Setting REST_SUB_REQUEST_PATH in msg context: " + requestPath);
}
synCtx.setProperty(RESTConstants.REST_SUB_REQUEST_PATH, requestPath);
// verb has been put into the cache.
if (resourceArray != null) {
for (String resourceString : resourceArray) {
VerbInfoDTO verbInfo;
if (isGatewayAPIResourceValidationEnabled) {
String apiCacheKey = APIUtil.getAPIInfoDTOCacheKey(apiContext, apiVersion);
if (!getResourceCache().containsKey(apiCacheKey)) {
break;
}
resourceCacheKey = APIUtil.getResourceInfoDTOCacheKey(apiContext, apiVersion, resourceString, httpMethod);
verbInfo = (VerbInfoDTO) getResourceCache().get(resourceCacheKey);
// Cache hit
if (verbInfo != null) {
if (log.isDebugEnabled()) {
log.debug("Found resource in Cache for key: " + resourceCacheKey);
}
verbInfoList.add(verbInfo);
} else {
if (log.isDebugEnabled()) {
log.debug("Resource not found in cache for key: " + resourceCacheKey);
}
}
}
}
if (resourceArray.size() == verbInfoList.size()) {
return verbInfoList;
}
} else {
API selectedApi = Utils.getSelectedAPI(synCtx);
Resource selectedResource = null;
String resourceString;
if (selectedApi != null) {
Resource[] selectedAPIResources = selectedApi.getResources();
Set<Resource> acceptableResources = new LinkedHashSet<Resource>();
for (Resource resource : selectedAPIResources) {
// If the requesting method is OPTIONS or if the Resource contains the requesting method
if (RESTConstants.METHOD_OPTIONS.equals(httpMethod) || (resource.getMethods() != null && Arrays.asList(resource.getMethods()).contains(httpMethod))) {
acceptableResources.add(resource);
}
}
if (acceptableResources.size() > 0) {
for (RESTDispatcher dispatcher : RESTUtils.getDispatchers()) {
Resource resource = dispatcher.findResource(synCtx, acceptableResources);
if (resource != null && Arrays.asList(resource.getMethods()).contains(httpMethod)) {
selectedResource = resource;
break;
}
}
}
}
if (selectedResource == null) {
// No matching resource found.
String msg = "Could not find matching resource for " + requestPath;
log.error(msg);
throw new ResourceNotFoundException(msg);
}
resourceString = selectedResource.getDispatcherHelper().getString();
resourceCacheKey = APIUtil.getResourceInfoDTOCacheKey(apiContext, apiVersion, resourceString, httpMethod);
if (log.isDebugEnabled()) {
log.debug("Selected Resource: " + resourceString);
}
// Set the elected resource
synCtx.setProperty(APIConstants.API_ELECTED_RESOURCE, resourceString);
if (isGatewayAPIResourceValidationEnabled) {
VerbInfoDTO verbInfo;
verbInfo = (VerbInfoDTO) getResourceCache().get(resourceCacheKey);
// Cache hit
if (verbInfo != null) {
if (log.isDebugEnabled()) {
log.debug("Got Resource from cache for key: " + resourceCacheKey);
}
verbInfoList.add(verbInfo);
return verbInfoList;
} else if (log.isDebugEnabled()) {
log.debug("Cache miss for Resource for key: " + resourceCacheKey);
}
}
}
String apiCacheKey = APIUtil.getAPIInfoDTOCacheKey(apiContext, apiVersion);
APIInfoDTO apiInfoDTO = null;
if (isGatewayAPIResourceValidationEnabled) {
apiInfoDTO = (APIInfoDTO) getResourceCache().get(apiCacheKey);
}
// Cache miss
if (apiInfoDTO == null) {
if (log.isDebugEnabled()) {
log.debug("Could not find API object in cache for key: " + apiCacheKey);
}
String apiType = (String) synCtx.getProperty(APIMgtGatewayConstants.API_TYPE);
if (APIConstants.ApiTypes.PRODUCT_API.name().equalsIgnoreCase(apiType)) {
apiInfoDTO = doGetAPIProductInfo(synCtx, apiContext, apiVersion);
} else {
apiInfoDTO = doGetAPIInfo(synCtx, apiContext, apiVersion);
}
if (isGatewayAPIResourceValidationEnabled) {
getResourceCache().put(apiCacheKey, apiInfoDTO);
}
}
if (apiInfoDTO.getResources() != null) {
for (ResourceInfoDTO resourceInfoDTO : apiInfoDTO.getResources()) {
Set<VerbInfoDTO> verbDTOList = resourceInfoDTO.getHttpVerbs();
for (VerbInfoDTO verb : verbDTOList) {
if (verb.getHttpVerb().equals(httpMethod)) {
for (String resourceString : resourceArray) {
if (isResourcePathMatching(resourceString, resourceInfoDTO)) {
resourceCacheKey = APIUtil.getResourceInfoDTOCacheKey(apiContext, apiVersion, resourceString, httpMethod);
verb.setRequestKey(resourceCacheKey);
verbInfoList.add(verb);
if (isGatewayAPIResourceValidationEnabled) {
// Set cache key in the message c\ontext so that it can be used by the subsequent handlers.
if (log.isDebugEnabled()) {
log.debug("Putting resource object in cache with key: " + resourceCacheKey);
}
getResourceCache().put(resourceCacheKey, verb);
synCtx.setProperty(APIConstants.API_RESOURCE_CACHE_KEY, resourceCacheKey);
}
}
}
}
}
}
}
if (verbInfoList.size() == 0) {
verbInfoList = null;
}
return verbInfoList;
}
use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.
the class InternalAPIKeyAuthenticator method authenticate.
@Override
public AuthenticationResponse authenticate(MessageContext synCtx) {
API retrievedApi = GatewayUtils.getAPI(synCtx);
if (retrievedApi != null) {
if (log.isDebugEnabled()) {
log.info("Internal Key Authentication initialized");
}
try {
// Extract internal from the request while removing it from the msg context.
String internalKey = extractInternalKey(synCtx);
if (StringUtils.isEmpty(internalKey)) {
return new AuthenticationResponse(false, false, true, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
}
OpenAPI openAPI = (OpenAPI) synCtx.getProperty(APIMgtGatewayConstants.OPEN_API_OBJECT);
if (openAPI == null && !APIConstants.GRAPHQL_API.equals(synCtx.getProperty(APIConstants.API_TYPE))) {
log.error("Swagger is missing in the gateway. " + "Therefore, Internal Key authentication cannot be performed.");
return new AuthenticationResponse(false, true, false, APISecurityConstants.API_AUTH_MISSING_OPEN_API_DEF, APISecurityConstants.API_AUTH_MISSING_OPEN_API_DEF_ERROR_MESSAGE);
}
JWTTokenPayloadInfo payloadInfo = null;
String[] splitToken = internalKey.split("\\.");
JWTClaimsSet payload;
SignedJWT signedJWT;
String tokenIdentifier;
JWSHeader jwsHeader;
String alias;
if (splitToken.length != 3) {
log.error("Internal Key does not have the format {header}.{payload}.{signature} ");
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
}
signedJWT = SignedJWT.parse(internalKey);
payload = signedJWT.getJWTClaimsSet();
tokenIdentifier = payload.getJWTID();
jwsHeader = signedJWT.getHeader();
if (jwsHeader != null && StringUtils.isNotEmpty(jwsHeader.getKeyID())) {
alias = jwsHeader.getKeyID();
} else {
alias = APIUtil.getInternalApiKeyAlias();
}
// Check if the decoded header contains type as 'InternalKey'.
if (!GatewayUtils.isInternalKey(payload)) {
if (log.isDebugEnabled()) {
log.debug("Invalid Internal Key token type. Internal Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
}
log.error("Invalid Internal Key token type.");
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
}
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);
String resourceCacheKey = APIUtil.getResourceInfoDTOCacheKey(apiContext, apiVersion, matchingResource, httpMethod);
VerbInfoDTO verbInfoDTO = new VerbInfoDTO();
verbInfoDTO.setHttpVerb(httpMethod);
// Not doing resource level authentication
verbInfoDTO.setAuthType(APIConstants.AUTH_NO_AUTHENTICATION);
verbInfoDTO.setRequestKey(resourceCacheKey);
verbInfoDTO.setThrottling(OpenAPIUtils.getResourceThrottlingTier(openAPI, synCtx));
List<VerbInfoDTO> verbInfoList = new ArrayList<>();
verbInfoList.add(verbInfoDTO);
synCtx.setProperty(APIConstants.VERB_INFO_DTO, verbInfoList);
String cacheKey = GatewayUtils.getAccessTokenCacheKey(tokenIdentifier, apiContext, apiVersion, matchingResource, httpMethod);
String tenantDomain = GatewayUtils.getTenantDomain();
boolean isVerified = false;
String cacheToken = (String) getGatewayInternalKeyCache().get(tokenIdentifier);
if (cacheToken != null) {
if (log.isDebugEnabled()) {
log.debug("Internal Key retrieved from the Internal Key cache.");
}
if (getGatewayInternalKeyDataCache().get(cacheKey) != null) {
// Token is found in the key cache
payloadInfo = (JWTTokenPayloadInfo) getGatewayInternalKeyDataCache().get(cacheKey);
String accessToken = payloadInfo.getAccessToken();
isVerified = accessToken.equals(internalKey);
}
} else if (getInvalidGatewayInternalKeyCache().get(tokenIdentifier) != null) {
if (log.isDebugEnabled()) {
log.debug("Internal Key retrieved from the invalid Internal Key cache. Internal Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
}
log.error("Invalid Internal Key." + GatewayUtils.getMaskedToken(splitToken[0]));
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
}
// Not found in cache or caching disabled
if (!isVerified) {
if (log.isDebugEnabled()) {
log.debug("Internal Key not found in the cache.");
}
isVerified = GatewayUtils.verifyTokenSignature(signedJWT, alias) && !GatewayUtils.isJwtTokenExpired(payload);
// Add token to tenant token cache
if (isVerified) {
getGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
} else {
getInvalidGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
}
if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
try {
// Start super tenant flow
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, true);
// Add token to super tenant token cache
if (isVerified) {
getGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
}
// If Internal Key signature is verified
if (isVerified) {
if (log.isDebugEnabled()) {
log.debug("Internal Key signature is verified.");
}
if (payloadInfo != null) {
// Internal Key is found in the key cache
payload = payloadInfo.getPayload();
if (GatewayUtils.isJwtTokenExpired(payload)) {
getGatewayInternalKeyCache().remove(tokenIdentifier);
getInvalidGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
log.error("Internal Key is expired");
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
}
} else {
// Retrieve payload from InternalKey
if (log.isDebugEnabled()) {
log.debug("InternalKey payload not found in the cache.");
}
JWTTokenPayloadInfo jwtTokenPayloadInfo = new JWTTokenPayloadInfo();
jwtTokenPayloadInfo.setPayload(payload);
jwtTokenPayloadInfo.setAccessToken(internalKey);
getGatewayInternalKeyDataCache().put(cacheKey, jwtTokenPayloadInfo);
}
JSONObject api = GatewayUtils.validateAPISubscription(apiContext, apiVersion, payload, splitToken, false);
if (log.isDebugEnabled()) {
log.debug("Internal Key authentication successful.");
}
AuthenticationContext authenticationContext = GatewayUtils.generateAuthenticationContext(tokenIdentifier, payload, api, retrievedApi.getApiTier());
APISecurityUtils.setAuthenticationContext(synCtx, authenticationContext);
if (log.isDebugEnabled()) {
log.debug("User is authorized to access the resource using Internal Key.");
}
return new AuthenticationResponse(true, true, false, 0, null);
}
if (log.isDebugEnabled()) {
log.debug("Internal Key signature verification failure. Internal Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
}
log.error("Invalid Internal Key. Signature verification failed.");
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
} catch (APISecurityException e) {
return new AuthenticationResponse(false, true, false, e.getErrorCode(), e.getMessage());
} catch (ParseException e) {
log.error("Error while parsing Internal Key", e);
return new AuthenticationResponse(false, true, false, APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
}
}
return new AuthenticationResponse(false, true, false, APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
}
use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.
the class ApiKeyAuthenticator method generateAndRetrieveBackendJWTToken.
private String generateAndRetrieveBackendJWTToken(String tokenSignature, JWTInfoDto jwtInfoDto) throws APISecurityException {
String endUserToken = null;
boolean valid = false;
String jwtTokenCacheKey = jwtInfoDto.getApiContext().concat(":").concat(jwtInfoDto.getVersion()).concat(":").concat(tokenSignature);
if (isGatewayTokenCacheEnabled) {
Object token = getGatewayApiKeyCache().get(jwtTokenCacheKey);
if (token != null) {
endUserToken = (String) token;
String[] splitToken = ((String) token).split("\\.");
JSONObject payload = new JSONObject(new String(Base64.getUrlDecoder().decode(splitToken[1])));
long exp = payload.getLong("exp");
long timestampSkew = OAuthServerConfiguration.getInstance().getTimeStampSkewInSeconds() * 1000;
valid = (exp - System.currentTimeMillis() > timestampSkew);
}
if (StringUtils.isEmpty(endUserToken) || !valid) {
try {
endUserToken = apiMgtGatewayJWTGenerator.generateToken(jwtInfoDto);
getGatewayApiKeyCache().put(jwtTokenCacheKey, endUserToken);
} catch (JWTGeneratorException e) {
log.error("Error while Generating Backend JWT", e);
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE, e);
}
}
} else {
try {
endUserToken = apiMgtGatewayJWTGenerator.generateToken(jwtInfoDto);
} catch (JWTGeneratorException e) {
log.error("Error while Generating Backend JWT", e);
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE, e);
}
}
return endUserToken;
}
use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.
the class ApiKeyAuthenticator method extractApiKey.
private String extractApiKey(MessageContext mCtx) throws APISecurityException {
org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) mCtx).getAxis2MessageContext();
String apiKey;
// check headers to get apikey
Map headers = (Map) (axis2MC.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS));
if (headers != null) {
apiKey = (String) headers.get(securityParam);
if (apiKey != null) {
// Remove apikey header from the request
headers.remove(securityParam);
return apiKey.trim();
}
}
// check query params to get apikey
try {
apiKey = new SynapseXPath("$url:apikey").stringValueOf(mCtx);
if (StringUtils.isNotBlank(apiKey)) {
String rest_url_postfix = (String) axis2MC.getProperty(NhttpConstants.REST_URL_POSTFIX);
rest_url_postfix = removeApiKeyFromQueryParameters(rest_url_postfix, URLEncoder.encode(apiKey));
axis2MC.setProperty(NhttpConstants.REST_URL_POSTFIX, rest_url_postfix);
return apiKey.trim();
} else {
if (log.isDebugEnabled()) {
log.debug("Api Key Authentication failed: Header or Query parameter with the name '".concat(securityParam).concat("' was not found."));
}
throw new APISecurityException(APISecurityConstants.API_AUTH_MISSING_CREDENTIALS, APISecurityConstants.API_AUTH_MISSING_CREDENTIALS_MESSAGE);
}
} catch (JaxenException e) {
if (log.isDebugEnabled()) {
log.debug("Error while retrieving apikey from the request query params.", e);
}
throw new APISecurityException(APISecurityConstants.API_AUTH_MISSING_CREDENTIALS, APISecurityConstants.API_AUTH_MISSING_CREDENTIALS_MESSAGE);
}
}
Aggregations