Skip to content

Commit

Permalink
Merge pull request #12443 from Chanuka-ChandraYapa/feature-throttle-p…
Browse files Browse the repository at this point in the history
…olicy-reset

[Feature] Throttle Policy Reset Support for APIM
  • Loading branch information
rmsamitha authored May 21, 2024
2 parents b844a8e + cbf8344 commit 50c2d46
Show file tree
Hide file tree
Showing 18 changed files with 1,292 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,16 @@ Set<SubscribedAPI> getPaginatedSubscribedAPIsByApplication(Application applicati
*/
Tier getThrottlePolicyByName(String name, int policyType, String organization) throws APIManagementException;

/**
* Send Application Policy Reset Event to Eventhub
*
* @param applicationId Application Identifier used by traffic manager
* @param userId Username for which the policy should be reset
* @param organization Tenant which application owner belongs to
*/
void resetApplicationThrottlePolicy(String applicationId, String userId, String organization)
throws APIManagementException;

/**
* Returns the API Chat execute call response as a string
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1948,6 +1948,7 @@ public enum RegistryResourceTypesForUI {
public static final String API_POLICY_API_LEVEL = "apiLevel";

public static final String BILLING_PLAN_FREE = "FREE";
public static final String POLICY_RESET = "reset";

public static final String BLOCKING_EVENT_TYPE = "wso2event";
public static final String BLOCKING_EVENT_FORMAT = "wso2event";
Expand Down Expand Up @@ -2769,6 +2770,7 @@ public enum EventType {
POLICY_CREATE,
POLICY_UPDATE,
POLICY_DELETE,
POLICY_RESET,
SUBSCRIPTIONS_CREATE,
SUBSCRIPTIONS_UPDATE,
SUBSCRIPTIONS_DELETE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder;
import org.wso2.carbon.apimgt.impl.monetization.DefaultMonetizationImpl;
import org.wso2.carbon.apimgt.impl.notifier.events.ApplicationEvent;
import org.wso2.carbon.apimgt.impl.notifier.events.ApplicationPolicyResetEvent;
import org.wso2.carbon.apimgt.impl.notifier.events.ApplicationRegistrationEvent;
import org.wso2.carbon.apimgt.impl.notifier.events.SubscriptionEvent;
import org.wso2.carbon.apimgt.impl.publishers.RevocationRequestPublisher;
Expand Down Expand Up @@ -4344,6 +4345,34 @@ public Tier getThrottlePolicyByName(String policyId, int policyType, String orga
return tier;
}

/**
* Send Application Policy Reset Event to Eventhub
*
* @param applicationId Application Identifier used by traffic manager
* @param userId Username for which the policy should be reset
* @param organization Tenant which application owner belongs to
*/
@Override
public void resetApplicationThrottlePolicy(String applicationId, String userId, String organization)
throws APIManagementException {
// Get the application
Application application = getApplicationByUUID(applicationId, organization);
String groupId = application.getGroupId();
int appId = application.getId();
String appTier = application.getTier();
// Check whether the application is accessible to the logged-in user
String loggedInUser = (userNameWithoutChange != null) ? userNameWithoutChange : username;
if (!validateApplication(loggedInUser, appId, groupId)) {
log.error("Application " + applicationId + " is not accessible to user " + loggedInUser);
throw new APIMgtAuthorizationFailedException("Application is not accessible to user " + loggedInUser);
}

ApplicationPolicyResetEvent applicationPolicyResetEvent = new ApplicationPolicyResetEvent(
UUID.randomUUID().toString(), System.currentTimeMillis(), APIConstants.EventType.POLICY_RESET.name(),
tenantId, organization, UUID.randomUUID().toString(), String.valueOf(appId), userId, appTier);
APIUtil.sendNotification(applicationPolicyResetEvent, APIConstants.NotifierType.POLICY.name());
}

/**
* Get host names with transport scheme mapping from Gateway Environments in api-manager.xml or from the tenant
* custom url config in registry. (For WebSockets)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.carbon.apimgt.impl.notifier.events;

import java.util.Objects;

import org.wso2.carbon.apimgt.impl.APIConstants.PolicyType;

/**
* An Event Object which can holds the data related to Application Policy and User which are required
* to publish to traffic manager for resetting the Application Throttle Policy.
*/

public class ApplicationPolicyResetEvent extends PolicyEvent {
private String uuid;
private String appId;
private String userId;
private String appTier;

public ApplicationPolicyResetEvent(String eventId, long timestamp, String type, int tenantId, String tenantDomain,
String uuid, String appId, String userId, String appTier) {
this.eventId = eventId;
this.timeStamp = timestamp;
this.type = type;
this.tenantId = tenantId;
this.uuid = uuid;
this.tenantDomain = tenantDomain;
this.appId = appId;
this.userId = userId;
this.appTier = appTier;
this.policyType = PolicyType.APPLICATION;
}

@Override
public String toString() {
return "ApplicationPolicyResetEvent{" +
", eventId='" + eventId + '\'' +
", timeStamp=" + timeStamp +
", type='" + type + '\'' +
", tenantId=" + tenantId +
", tenantDomain='" + tenantDomain + '\'' +
", appId='" + appId + '\'' +
", userId='" + userId + '\'' +
", appTier='" + appTier + '\'' +
'}';
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ApplicationPolicyResetEvent)) return false;
ApplicationPolicyResetEvent that = (ApplicationPolicyResetEvent) o;
return
getAppId().equals(that.getAppId()) &&
getUserId().equals(that.getUserId()) &&
getAppTier().equals(that.getAppTier());
}

@Override
public int hashCode() {
return Objects.hash( getAppId(), getUserId(), getAppTier());
}


public String getUuid() {

return uuid;
}

public void setUuid(String uuid) {

this.uuid = uuid;
}

public String getAppId() {
return appId;
}

public void setAppId(String appId) {
this.appId = appId;
}

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}

public String getAppTier() {
return appTier;
}

public void setAppTier(String appTier) {
this.appTier = appTier;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,23 @@ public void testUpdateApplication() throws APIManagementException {
}
}

@Test
public void testResetApplicationThrottlePolicy() throws APIManagementException {
Application application = new Application("app", new Subscriber("sub1"));
application.setGroupId("testGroupId");
application.setId(5);
application.setTier("testTier");

Mockito.when(apiMgtDAO.getApplicationByUUID(Mockito.anyString())).thenReturn(application);
APIConsumerImpl apiConsumer = new APIConsumerImplWrapper(apiMgtDAO);
try {
apiConsumer.resetApplicationThrottlePolicy("1", "testUser", "testOrg");
Assert.fail("API management exception not thrown for error scenario");
} catch (APIManagementException e) {
Assert.assertTrue(e.getMessage().contains("Application is not accessible to user"));
}
}

@Test
public void testTokenTypeChangeWhenUpdatingApplications() throws APIManagementException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3143,6 +3143,55 @@ paths:
- lang: Curl
source: curl -k "https://localhost:9443/api/am/devportal/v3/throttling-policies/application/10PerMin"

######################################################
# The "Throttling Policy Reset" resource APIs
######################################################
/applications/{applicationId}/reset-throttle-policy:
post:
tags:
- Applications
summary: Reset Application-Level Throttle Policy
description: |
This operation can be used to reset the application-level throttle policy for a specific user.
parameters:
- $ref: '#/components/parameters/applicationId'
requestBody:
description: |
Payload for which the application-level throttle policy needs to be reset
content:
application/json:
schema:
$ref: '#/components/schemas/ApplicationThrottleReset'
required: true
responses:
200:
description: OK. Application-level throttle policy reset successfully
content: {}
400:
$ref: '#/components/responses/BadRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
description: |
Forbidden.
The request must be conditional but no condition has been specified.
content: { }
404:
$ref: '#/components/responses/NotFound'
500:
$ref: '#/components/responses/InternalServerError'
security:
- OAuth2Security:
- apim:app_manage
- apim:subscribe
x-code-samples:
- lang: Curl
source: 'curl -k \
-H "Authorization: Bearer 80249337-fe7c-3c66-bde6-ed431c144372" \
-H "Content-Type: application/json" -X POST \
-d @payload.json \
"https://localhost:9443/api/am/devportal/v3/application/37dd21cc-631e-4c73-bf73-c59cc7087a63/reset-throttle-policy"'

######################################################
# The "Tag Collection" resource API
######################################################
Expand Down Expand Up @@ -3772,6 +3821,14 @@ paths:

components:
schemas:
ApplicationThrottleReset:
title: Reset application level throttling
type: object
properties:
userName:
type: string
description: The username for which the throttle policy needs to be reset
example: admin
APIList:
title: API List
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationKeyMappingRequestDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationKeyReGenerateResponseDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationListDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationThrottleResetDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationTokenDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationTokenGenerateRequestDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ErrorDTO;
Expand Down Expand Up @@ -433,6 +434,27 @@ public Response applicationsApplicationIdOauthKeysKeyMappingIdRegenerateSecretPo
return delegate.applicationsApplicationIdPut(applicationId, applicationDTO, ifMatch, securityContext);
}

@POST
@Path("/{applicationId}/reset-throttle-policy")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "Reset Application-Level Throttle Policy", notes = "This operation can be used to reset the application-level throttle policy for a specific user. ", response = Void.class, authorizations = {
@Authorization(value = "OAuth2Security", scopes = {
@AuthorizationScope(scope = "apim:app_manage", description = "Retrieve, Manage and Import, Export applications"),
@AuthorizationScope(scope = "apim:subscribe", description = "Subscribe API")
})
}, tags={ "Applications", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK. Application-level throttle policy reset successfully", response = Void.class),
@ApiResponse(code = 400, message = "Bad Request. Invalid request or validation error.", response = ErrorDTO.class),
@ApiResponse(code = 401, message = "Unauthorized. The user is not authorized.", response = ErrorDTO.class),
@ApiResponse(code = 403, message = "Forbidden. The request must be conditional but no condition has been specified. ", response = Void.class),
@ApiResponse(code = 404, message = "Not Found. The specified resource does not exist.", response = ErrorDTO.class),
@ApiResponse(code = 500, message = "Internal Server Error.", response = ErrorDTO.class) })
public Response applicationsApplicationIdResetThrottlePolicyPost(@ApiParam(value = "Application Identifier consisting of the UUID of the Application. ",required=true) @PathParam("applicationId") String applicationId, @ApiParam(value = "Payload for which the application-level throttle policy needs to be reset " ,required=true) ApplicationThrottleResetDTO applicationThrottleResetDTO) throws APIManagementException{
return delegate.applicationsApplicationIdResetThrottlePolicyPost(applicationId, applicationThrottleResetDTO, securityContext);
}

@GET
@Path("/export")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationKeyMappingRequestDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationKeyReGenerateResponseDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationListDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationThrottleResetDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationTokenDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationTokenGenerateRequestDTO;
import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ErrorDTO;
Expand Down Expand Up @@ -56,6 +57,7 @@ public interface ApplicationsApiService {
public Response applicationsApplicationIdOauthKeysKeyMappingIdPut(String applicationId, String keyMappingId, ApplicationKeyDTO applicationKeyDTO, MessageContext messageContext) throws APIManagementException;
public Response applicationsApplicationIdOauthKeysKeyMappingIdRegenerateSecretPost(String applicationId, String keyMappingId, MessageContext messageContext) throws APIManagementException;
public Response applicationsApplicationIdPut(String applicationId, ApplicationDTO applicationDTO, String ifMatch, MessageContext messageContext) throws APIManagementException;
public Response applicationsApplicationIdResetThrottlePolicyPost(String applicationId, ApplicationThrottleResetDTO applicationThrottleResetDTO, MessageContext messageContext) throws APIManagementException;
public Response applicationsExportGet(String appName, String appOwner, Boolean withKeys, String format, MessageContext messageContext) throws APIManagementException;
public Response applicationsGet(String groupId, String query, String sortBy, String sortOrder, Integer limit, Integer offset, String ifNoneMatch, MessageContext messageContext) throws APIManagementException;
public Response applicationsImportPost(InputStream fileInputStream, Attachment fileDetail, Boolean preserveOwner, Boolean skipSubscriptions, String appOwner, Boolean skipApplicationKeys, Boolean update, MessageContext messageContext) throws APIManagementException;
Expand Down
Loading

0 comments on commit 50c2d46

Please sign in to comment.