Skip to content

Commit d3d41bd

Browse files
author
Naduni Pamudika
committed
Fix review comments and did changes to admin rest apis
1 parent 1afd055 commit d3d41bd

File tree

14 files changed

+372
-80
lines changed

14 files changed

+372
-80
lines changed

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/apikey/ApiKeyAuthenticator.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ public AuthenticationResponse authenticate(MessageContext synCtx) {
180180
ApiKeyAuthenticatorUtils.checkTokenExpired(isGatewayTokenCacheEnabled, cacheKey, tokenIdentifier, apiKey,
181181
tenantDomain, payload);
182182
ApiKeyAuthenticatorUtils.validateAPIKeyRestrictions(payload, GatewayUtils.getIp(axis2MessageContext),
183-
apiContext, apiVersion, referer, null);
184-
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = GatewayUtils.validateAPISubscription(apiContext, apiVersion, payload,
185-
null, 0, splitToken[0]);
183+
apiContext, apiVersion, referer);
184+
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = GatewayUtils.validateAPISubscription(apiContext,
185+
apiVersion, payload, splitToken[0]);
186186
String endUserToken = ApiKeyAuthenticatorUtils.getEndUserToken(apiKeyValidationInfoDTO, jwtConfigurationDto, apiKey,
187187
signedJWT, payload, tokenIdentifier, apiContext, apiVersion, isGatewayTokenCacheEnabled);
188188
AuthenticationContext authenticationContext = GatewayUtils.generateAuthenticationContext(tokenIdentifier,
@@ -271,7 +271,7 @@ public AuthenticationContext validateOpaqueApiKey(String apiKey, String apiConte
271271
// Validate subscription
272272
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = null;
273273
try {
274-
apiKeyValidationInfoDTO = GatewayUtils.validateAPISubscription(apiContext, apiVersion, null, apiKeyInfo.getKeyType(),
274+
apiKeyValidationInfoDTO = GatewayUtils.validateAPISubscription(apiContext, apiVersion, apiKeyInfo.getKeyType(),
275275
apiKeyInfo.getAppId(), apiKey);
276276
if (apiKeyValidationInfoDTO != null && apiKeyValidationInfoDTO.isAuthorized()) {
277277
if (log.isDebugEnabled()) {
@@ -293,7 +293,7 @@ public AuthenticationContext validateOpaqueApiKey(String apiKey, String apiConte
293293
}
294294

295295
// Check for permittedIP and permittedReferrers
296-
ApiKeyAuthenticatorUtils.validateAPIKeyRestrictions(null, ip,
296+
ApiKeyAuthenticatorUtils.validateAPIKeyRestrictions(ip,
297297
apiContext, apiVersion, referrer, apiKeyInfo.getAdditionalProperties());
298298

299299
// TODO: Check for api key expiry and status is ACTIVE

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/Authentication/ApiKeyAuthenticator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ public InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMes
110110
apiKey, tenantDomain, payload);
111111
ApiKeyAuthenticatorUtils.validateAPIKeyRestrictions(payload, inboundMessageContext.getUserIP(),
112112
apiContext, apiVersion, inboundMessageContext.getRequestHeaders().
113-
get(APIMgtGatewayConstants.REFERER), null);
113+
get(APIMgtGatewayConstants.REFERER));
114114
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = GatewayUtils.validateAPISubscription(apiContext, apiVersion,
115-
payload, null, 0, splitToken[0]);
115+
payload, splitToken[0]);
116116
String endUserToken = ApiKeyAuthenticatorUtils.getEndUserToken(apiKeyValidationInfoDTO, jwtConfigurationDto,
117117
apiKey, signedJWT, payload, tokenIdentifier, apiContext, apiVersion, isGatewayTokenCacheEnabled);
118118
AuthenticationContext authenticationContext = GatewayUtils.generateAuthenticationContext(tokenIdentifier,

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/utils/ApiKeyAuthenticatorUtils.java

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,11 @@ public static void checkTokenExpired(boolean isGatewayTokenCacheEnabled, String
277277
* @param apiContext The API context.
278278
* @param apiVersion The API version.
279279
* @param referer The http referer.
280-
* @param additionalProperties Additional properties sent with an opaque API key.
281280
* @throws APISecurityException If the API Key is not allowed to access the API.
282281
* @throws APIManagementException If an error occurs while validating the restrictions.
283282
*/
284283
public static void validateAPIKeyRestrictions(JWTClaimsSet payload, String clientIP, String apiContext,
285-
String apiVersion, String referer, Map<String, String> additionalProperties)
284+
String apiVersion, String referer)
286285
throws APISecurityException, APIManagementException {
287286

288287
String permittedIPList = null;
@@ -294,12 +293,69 @@ public static void validateAPIKeyRestrictions(JWTClaimsSet payload, String clien
294293
if (payload.getClaim(APIConstants.JwtTokenConstants.PERMITTED_REFERER) != null) {
295294
permittedRefererList = (String) payload.getClaim(APIConstants.JwtTokenConstants.PERMITTED_REFERER);
296295
}
297-
} else {
298-
if (additionalProperties != null) {
299-
// Taking values from the DB for an opaque API key
300-
permittedIPList = additionalProperties.get(APIConstants.JwtTokenConstants.PERMITTED_IP);
301-
permittedRefererList = additionalProperties.get(APIConstants.JwtTokenConstants.PERMITTED_REFERER);
296+
}
297+
if (StringUtils.isNotEmpty(permittedIPList)) {
298+
// Validate client IP against permitted IPs
299+
if (StringUtils.isNotEmpty(clientIP)) {
300+
for (String restrictedIP : permittedIPList.split(",")) {
301+
if (APIUtil.isIpInNetwork(clientIP, restrictedIP.trim())) {
302+
// Client IP is allowed
303+
return;
304+
}
305+
}
306+
if (log.isDebugEnabled()) {
307+
if (StringUtils.isNotEmpty(clientIP)) {
308+
log.debug("Invocations to API: " + apiContext + ":" + apiVersion +
309+
" is not permitted for client with IP: " + clientIP);
310+
}
311+
}
312+
throw new APISecurityException(APISecurityConstants.API_AUTH_FORBIDDEN,
313+
"Access forbidden for the invocations");
314+
}
315+
}
316+
if (StringUtils.isNotEmpty(permittedRefererList)) {
317+
// Validate http referer against the permitted referrers
318+
if (StringUtils.isNotEmpty(referer)) {
319+
for (String restrictedReferer : permittedRefererList.split(",")) {
320+
String restrictedRefererRegExp = restrictedReferer.trim()
321+
.replace("*", "[^ ]*");
322+
if (referer.matches(restrictedRefererRegExp)) {
323+
// Referer is allowed
324+
return;
325+
}
326+
}
327+
if (log.isDebugEnabled()) {
328+
if (StringUtils.isNotEmpty(referer)) {
329+
log.debug("Invocations to API: " + apiContext + ":" + apiVersion +
330+
" is not permitted for referer: " + referer);
331+
}
332+
}
302333
}
334+
throw new APISecurityException(APISecurityConstants.API_AUTH_FORBIDDEN,
335+
"Access forbidden for the invocations");
336+
}
337+
}
338+
339+
/**
340+
* This method is used to validate the API Key against the given restrictions.
341+
* @param clientIP The client IP.
342+
* @param apiContext The API context.
343+
* @param apiVersion The API version.
344+
* @param referer The http referer.
345+
* @param additionalProperties Additional properties sent with an opaque API key.
346+
* @throws APISecurityException If the API Key is not allowed to access the API.
347+
* @throws APIManagementException If an error occurs while validating the restrictions.
348+
*/
349+
public static void validateAPIKeyRestrictions(String clientIP, String apiContext,
350+
String apiVersion, String referer, Map<String, String> additionalProperties)
351+
throws APISecurityException {
352+
353+
String permittedIPList = null;
354+
String permittedRefererList = null;
355+
if (additionalProperties != null) {
356+
// Taking values from the DB for an opaque API key
357+
permittedIPList = additionalProperties.get(APIConstants.JwtTokenConstants.PERMITTED_IP);
358+
permittedRefererList = additionalProperties.get(APIConstants.JwtTokenConstants.PERMITTED_REFERER);
303359
}
304360
if (StringUtils.isNotEmpty(permittedIPList)) {
305361
// Validate client IP against permitted IPs

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/utils/GatewayUtils.java

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -891,29 +891,20 @@ public static JSONObject validateAPISubscription(String apiContext, String apiVe
891891
* @param apiContext API context
892892
* @param apiVersion API version
893893
* @param payload The payload of the JWT token
894-
* @param type The key type
895-
* @param applicationId Application Id
896894
* @param token The token which was used to invoke the API
897895
* @return an APIKeyValidationInfoDTO containing APIKey validation information.
898896
* If the subscription information is not found, return a null object.
899897
* @throws APISecurityException if the user is not subscribed to the API
900898
*/
901899
public static APIKeyValidationInfoDTO validateAPISubscription(String apiContext, String apiVersion, JWTClaimsSet payload,
902-
String type, int applicationId, String token)
900+
String token)
903901
throws APISecurityException {
904902

905903
APIKeyValidator apiKeyValidator = new APIKeyValidator();
906904
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = null;
907-
String keyType;
908-
if (type != null) {
909-
keyType = type;
910-
} else {
911-
keyType = (String) payload.getClaim(APIConstants.JwtTokenConstants.KEY_TYPE);
912-
}
905+
String keyType = (String) payload.getClaim(APIConstants.JwtTokenConstants.KEY_TYPE);
913906
int appId = 0;
914-
if (applicationId != 0) {
915-
appId = applicationId;
916-
} else if (payload.getClaim(APIConstants.JwtTokenConstants.APPLICATION) != null) {
907+
if (payload.getClaim(APIConstants.JwtTokenConstants.APPLICATION) != null) {
917908
try {
918909
Map<String, Object> applicationObjMap =
919910
payload.getJSONObjectClaim(APIConstants.JwtTokenConstants.APPLICATION);
@@ -949,6 +940,53 @@ public static APIKeyValidationInfoDTO validateAPISubscription(String apiContext,
949940
return apiKeyValidationInfoDTO;
950941
}
951942

943+
/**
944+
* Validate whether the user is subscribed to the invoked API. If subscribed, return a APIKeyValidationInfoDTO
945+
* object containing the API information to authenticate API Keys.
946+
*
947+
* @param apiContext API context
948+
* @param apiVersion API version
949+
* @param keyType The key type
950+
* @param applicationId Application Id
951+
* @param apiKey The api key which was used to invoke the API
952+
* @return an APIKeyValidationInfoDTO containing APIKey validation information.
953+
* If the subscription information is not found, return a null object.
954+
* @throws APISecurityException if the user is not subscribed to the API
955+
*/
956+
public static APIKeyValidationInfoDTO validateAPISubscription(String apiContext, String apiVersion, String keyType,
957+
int applicationId, String apiKey)
958+
throws APISecurityException {
959+
960+
APIKeyValidator apiKeyValidator = new APIKeyValidator();
961+
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = null;
962+
int appId = 0;
963+
if (applicationId != 0) {
964+
appId = applicationId;
965+
}
966+
// Validate subscription
967+
// If the appId is equal to 0 then it's an internal key
968+
if (appId != 0) {
969+
apiKeyValidationInfoDTO =
970+
apiKeyValidator.validateSubscription(apiContext, apiVersion, appId, getTenantDomain(), keyType);
971+
if (apiKeyValidationInfoDTO.isAuthorized()) {
972+
if (log.isDebugEnabled()) {
973+
log.debug("User is subscribed to the API: " + apiContext + ", " +
974+
"version: " + apiVersion + ". Token: " + getMaskedToken(apiKey));
975+
}
976+
apiKeyValidationInfoDTO.setType(keyType);
977+
} else {
978+
if (log.isDebugEnabled()) {
979+
log.debug("User is not subscribed to access the API: " + apiContext +
980+
", version: " + apiVersion + ". Token: " + getMaskedToken(apiKey));
981+
}
982+
log.error("User is not subscribed to access the API.");
983+
throw new APISecurityException(APISecurityConstants.API_AUTH_FORBIDDEN,
984+
APISecurityConstants.API_AUTH_FORBIDDEN_MESSAGE);
985+
}
986+
}
987+
return apiKeyValidationInfoDTO;
988+
}
989+
952990
/**
953991
* Verify the JWT token signature.
954992
*

components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/ApiKeysApi.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ public class ApiKeysApi {
3737

3838

3939
@DELETE
40-
@Path("/{applicationId}/{keyType}/{keyDisplayName}")
40+
@Path("/{apiId}/{applicationId}/{keyType}/{keyDisplayName}")
4141

4242
@Produces({ "application/json" })
43-
@ApiOperation(value = "Revoke API Key", notes = "Revoke an API Key for the application ", response = Void.class, authorizations = {
43+
@ApiOperation(value = "Revoke an API Key", notes = "Revoke an API Key for the API ", response = Void.class, authorizations = {
4444
@Authorization(value = "OAuth2Security", scopes = {
4545
@AuthorizationScope(scope = "apim:admin", description = "Manage all admin operations")
4646
})
@@ -49,8 +49,8 @@ public class ApiKeysApi {
4949
@ApiResponse(code = 200, message = "OK. Api key revoked successfully. ", response = Void.class),
5050
@ApiResponse(code = 400, message = "Bad Request. Invalid request or validation error.", response = ErrorDTO.class),
5151
@ApiResponse(code = 412, message = "Precondition Failed. The request has not been performed because one of the preconditions is not met.", response = ErrorDTO.class) })
52-
public Response apiKeysApplicationIdKeyTypeKeyDisplayNameDelete(@ApiParam(value = "Application UUID ",required=true) @PathParam("applicationId") String applicationId, @ApiParam(value = "**Application Key Type** standing for the type of the keys (i.e. Production or Sandbox). ",required=true, allowableValues="PRODUCTION, SANDBOX") @PathParam("keyType") String keyType, @ApiParam(value = "Name of the API key. ",required=true) @PathParam("keyDisplayName") String keyDisplayName) throws APIManagementException{
53-
return delegate.apiKeysApplicationIdKeyTypeKeyDisplayNameDelete(applicationId, keyType, keyDisplayName, securityContext);
52+
public Response apiKeysApiIdApplicationIdKeyTypeKeyDisplayNameDelete(@ApiParam(value = "**API ID** consisting of the **UUID** of the API. ",required=true) @PathParam("apiId") String apiId, @ApiParam(value = "Application UUID ",required=true) @PathParam("applicationId") String applicationId, @ApiParam(value = "**Application Key Type** standing for the type of the keys (i.e. Production or Sandbox). ",required=true, allowableValues="PRODUCTION, SANDBOX") @PathParam("keyType") String keyType, @ApiParam(value = "Name of the API key. URL-encode this value if it contains reserved path characters. ",required=true) @PathParam("keyDisplayName") String keyDisplayName) throws APIManagementException{
53+
return delegate.apiKeysApiIdApplicationIdKeyTypeKeyDisplayNameDelete(apiId, applicationId, keyType, keyDisplayName, securityContext);
5454
}
5555

5656
@GET

components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/ApiKeysApiService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121

2222

2323
public interface ApiKeysApiService {
24-
public Response apiKeysApplicationIdKeyTypeKeyDisplayNameDelete(String applicationId, String keyType, String keyDisplayName, MessageContext messageContext) throws APIManagementException;
24+
public Response apiKeysApiIdApplicationIdKeyTypeKeyDisplayNameDelete(String apiId, String applicationId, String keyType, String keyDisplayName, MessageContext messageContext) throws APIManagementException;
2525
public Response apiKeysGet(MessageContext messageContext) throws APIManagementException;
2626
}

0 commit comments

Comments
 (0)