Skip to content

Commit

Permalink
Merge pull request #12539 from RakhithaRR/disable-sub-validation-final
Browse files Browse the repository at this point in the history
Implement subscription validation disabling for OAuth tokens
  • Loading branch information
RakhithaRR authored Sep 19, 2024
2 parents 45c9c46 + 59d786e commit 3754885
Show file tree
Hide file tree
Showing 53 changed files with 1,112 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,15 @@ Map<String, Object> searchPaginatedAPIProducts(String searchQuery, String tenant
*/
String getSecuritySchemeOfAPI(String uuid, String organization) throws APIManagementException;

/**
* Returns whether subscription validation is disabled for an API
*
* @param uuid UUID of the API
* @return whether subscription validation is disabled
* @throws APIManagementException if failed get API from APIIdentifier
*/
boolean isSubscriptionValidationDisabled(String uuid) throws APIManagementException;

/**
* Returns details of an API
* @param uuid UUID of the API's registry artifact
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class API implements CacheableEntity<String> {
private String revision;
private String organization;
private Set<OperationPolicy> apiPolicies = new HashSet<>();
private boolean isSubscriptionValidationDisabled = false;

public String getRevision() {

Expand Down Expand Up @@ -213,4 +214,12 @@ public void setApiPolicy(OperationPolicy apiPolicy) {
public Set<OperationPolicy> getApiPolicies() {
return apiPolicies;
}

public boolean isSubscriptionValidationDisabled() {
return isSubscriptionValidationDisabled;
}

public void setSubscriptionValidationDisabled(boolean subscriptionValidationDisabled) {
isSubscriptionValidationDisabled = subscriptionValidationDisabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ public final class APIConstants {
public static final String API_TENANT_CONF_DEFAULT_SUBSCRIPTION_TIER = "DefaultSubscriptionLevelTier";

public static final String API_TENANT_CONF_EXPOSE_ENDPOINT_PASSWORD = "ExposeEndpointPassword";
public static final String API_TENANT_CONF_ALLOW_SUBSCRIPTION_VALIDATION_DISABLING
= "AllowSubscriptionValidationDisabling";

public static final String API_CATEGORY_FREE = "Free";

Expand Down Expand Up @@ -816,6 +818,8 @@ private Permissions() {
API_KEY_VALIDATOR + "EnableProvisionedAppValidation";
public static final String API_KEY_SUBSCRIPTION_VALIDATION_ENABLED =
API_KEY_VALIDATOR + "EnableAPIKeySubscriptionValidation";
public static final String ALLOW_SUBSCRIPTION_VALIDATION_DISABLING = API_KEY_VALIDATOR +
"AllowSubscriptionValidationDisabling";
public static final String KEY_MANAGER_OAUTH2_SCOPES_REST_API_BASE_PATH = "/api/identity/oauth2/v1.0/scopes";
public static final String KEY_MANAGER_OAUTH2_SCOPES_SCOPE_NAME_PARAM = "{scope_name}";
public static final String KEY_MANAGER_OAUTH2_SCOPES_REST_API_SCOPE_NAME = "/name/"
Expand Down Expand Up @@ -976,6 +980,10 @@ private Permissions() {
public static final String BASIC_AUTH_APPLICATION_OWNER = " BasicAuthApplicationOwner";
public static final String MUTUAL_SSL_AUTH_APPLICATION_NAME = "MutualSSLAuthApplication";
public static final String MUTUAL_SSL_AUTH_APPLICATION_OWNER = "MutualSSLAuthApplicationOwner";
public static final String SUBSCRIPTIONLESS_APPLICATION_NAME = "SubscriptionLessApplication";
public static final String SUBSCRIPTIONLESS_APPLICATION_OWNER = "SubscriptionLessApplicationOwner";
public static final String SUBSCRIPTIONLESS_APPLICATION_DESCRIPTION = "This application is used to internally" +
" subscribe to APIs when subscription validation is disabled";

public static final QName POLICY_ELEMENT = new QName("http://schemas.xmlsoap.org/ws/2004/09/policy",
"Policy");
Expand Down Expand Up @@ -1237,6 +1245,7 @@ public static class SubscriptionValidationResources {
public static final String APPLICATIONS = "/applications";
public static final String SUBSCRIPTIONS = "/subscriptions";
public static final String SUBSCRIBERS = "/subscribers";
public static final String SUBSCRIBE_INTERNAL = "/subscribe-internal";
public static final String APPLICATION_KEY_MAPPINGS = "/application-key-mappings";
public static final String APPLICATION_POLICIES = "/application-policies";
public static final String API_POLICIES = "/api-policies";
Expand Down Expand Up @@ -1918,11 +1927,13 @@ public enum RegistryResourceTypesForUI {
public static final String DEFAULT_SUB_POLICY_BRONZE = "Bronze";
public static final String DEFAULT_SUB_POLICY_UNLIMITED = "Unlimited";
public static final String DEFAULT_SUB_POLICY_UNAUTHENTICATED = "Unauthenticated";
public static final String DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS = "DefaultSubscriptionless";

public static final String DEFAULT_SUB_POLICY_ASYNC_GOLD = "AsyncGold";
public static final String DEFAULT_SUB_POLICY_ASYNC_SILVER = "AsyncSilver";
public static final String DEFAULT_SUB_POLICY_ASYNC_BRONZE = "AsyncBronze";
public static final String DEFAULT_SUB_POLICY_ASYNC_UNLIMITED = "AsyncUnlimited";
public static final String DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS = "AsyncDefaultSubscriptionless";

public static final String DEFAULT_SUB_POLICY_ASYNC_WH_GOLD = "AsyncWHGold";
public static final String DEFAULT_SUB_POLICY_ASYNC_WH_SILVER = "AsyncWHSilver";
Expand All @@ -1934,11 +1945,15 @@ public enum RegistryResourceTypesForUI {
public static final String DEFAULT_SUB_POLICY_BRONZE_DESC = "Allows 1000 requests per minute";
public static final String DEFAULT_SUB_POLICY_UNLIMITED_DESC = "Allows unlimited requests";
public static final String DEFAULT_SUB_POLICY_UNAUTHENTICATED_DESC = "Allows 500 request(s) per minute";
public static final String DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS_DESC =
"Allows 10000 requests per minute when subscription validation is disabled";

public static final String DEFAULT_SUB_POLICY_ASYNC_GOLD_DESC = "Allows 50000 events per day";
public static final String DEFAULT_SUB_POLICY_ASYNC_SILVER_DESC = "Allows 25000 events per day";
public static final String DEFAULT_SUB_POLICY_ASYNC_BRONZE_DESC = "Allows 5000 events per day";
public static final String DEFAULT_SUB_POLICY_ASYNC_UNLIMITED_DESC = "Allows unlimited events";
public static final String DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS_DESC =
"Allows 10000 events per day when subscription validation is disabled";

public static final String DEFAULT_SUB_POLICY_ASYNC_WH_GOLD_DESC = "Allows 10000 events per month and " +
"1000 active subscriptions";
Expand Down Expand Up @@ -2074,6 +2089,7 @@ public static class AdvancedThrottleConstants {
public static final String TRUE = "true";
public static final String ADD = "add";
public static final String ENABLE_POLICY_DEPLOYMENT = "EnablePolicyDeployment";
public static final String ENABLE_POLICY_RECREATE = "EnablePolicyRecreationOnStartup";
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,11 @@ private void setThrottleProperties(OMElement element) {
if (enablePolicyDeployElement != null) {
throttleProperties.setEnablePolicyDeployment(Boolean.parseBoolean(enablePolicyDeployElement.getText()));
}
OMElement enablePolicyRecreateElement = throttleConfigurationElement
.getFirstChildWithName(new QName(APIConstants.AdvancedThrottleConstants.ENABLE_POLICY_RECREATE));
if (enablePolicyRecreateElement != null) {
throttleProperties.setEnablePolicyRecreate(Boolean.parseBoolean(enablePolicyRecreateElement.getText()));
}
// Check subscription spike arrest enable
OMElement enabledSubscriptionLevelSpikeArrestElement = throttleConfigurationElement
.getFirstChildWithName(new QName(APIConstants.AdvancedThrottleConstants
Expand Down Expand Up @@ -1497,6 +1502,13 @@ private void setThrottleProperties(OMElement element) {
defaultThrottleTierLimits.put(APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED,
Long.parseLong(unauthenticatedTierElement.getText()));
}

OMElement subscriptionlessTierElement = subscriptionPolicyLimits.getFirstChildWithName(new
QName(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS));
if (subscriptionlessTierElement != null) {
defaultThrottleTierLimits.put(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS,
Long.parseLong(subscriptionlessTierElement.getText()));
}
}

OMElement applicationPolicyLimits = defaultTierLimits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5215,6 +5215,12 @@ public String getSecuritySchemeOfAPI(String uuid, String organization) throws AP
}
}

@Override
public boolean isSubscriptionValidationDisabled(String uuid) throws APIManagementException {
String status = apiMgtDAO.getSubscriptionValidationStatus(uuid);
return !"ENABLED".equalsIgnoreCase(status);
}

@Override
public API getAPIbyUUID(String uuid, String organization) throws APIManagementException {
Organization org = new Organization(organization);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5586,6 +5586,8 @@ public int addAPI(API api, int tenantId, String organization) throws APIManageme
prepStmt.setString(12, organization);
prepStmt.setString(13, api.getGatewayVendor());
prepStmt.setString(14, api.getVersionTimestamp());
prepStmt.setString(15,
APIUtil.setSubscriptionValidationStatusBeforeInsert(api.getAvailableTiers()));
prepStmt.execute();

rs = prepStmt.getGeneratedKeys();
Expand Down Expand Up @@ -7127,7 +7129,9 @@ public void updateAPI(API api, String username) throws APIManagementException {
prepStmt.setString(6, api.getApiLevelPolicy());
prepStmt.setString(7, api.getType());
prepStmt.setString(8, api.getGatewayVendor());
prepStmt.setString(9, api.getUuid());
prepStmt.setString(9,
APIUtil.setSubscriptionValidationStatusBeforeInsert(api.getAvailableTiers()));
prepStmt.setString(10, api.getUuid());
prepStmt.execute();

if (api.isDefaultVersion() ^ api.getId().getVersion().equals(previousDefaultVersion)) { //A change has
Expand Down Expand Up @@ -14982,6 +14986,8 @@ public void addAPIProduct(APIProduct apiProduct, String organization) throws API
prepStmtAddAPIProduct.setString(12, organization);
prepStmtAddAPIProduct.setString(13, apiProduct.getGatewayVendor());
prepStmtAddAPIProduct.setString(14, apiProduct.getVersionTimestamp());
prepStmtAddAPIProduct.setString(15,
APIUtil.setSubscriptionValidationStatusBeforeInsert(apiProduct.getAvailableTiers()));
prepStmtAddAPIProduct.execute();

rs = prepStmtAddAPIProduct.getGeneratedKeys();
Expand Down Expand Up @@ -15382,10 +15388,12 @@ public void updateAPIProduct(APIProduct product, String username) throws APIMana
ps.setString(2, username);
ps.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
ps.setString(4, product.getGatewayVendor());
ps.setString(5,
APIUtil.setSubscriptionValidationStatusBeforeInsert(product.getAvailableTiers()));
APIProductIdentifier identifier = product.getId();
ps.setString(5, identifier.getName());
ps.setString(6, APIUtil.replaceEmailDomainBack(identifier.getProviderName()));
ps.setString(7, identifier.getVersion());
ps.setString(6, identifier.getName());
ps.setString(7, APIUtil.replaceEmailDomainBack(identifier.getProviderName()));
ps.setString(8, identifier.getVersion());
ps.executeUpdate();

int productId = getAPIID(product.getUuid(), conn);
Expand Down Expand Up @@ -15835,6 +15843,24 @@ public BotDetectionData getBotDetectionAlertSubscription(String field, String va
return alertSubscription;
}

public String getSubscriptionValidationStatus(String apiUuid) throws APIManagementException {
String status = null;
String query = SQLConstants.GET_SUBSCRIPTION_VALIDATION_STATUS_SQL;

try (Connection connection = APIMgtDBUtil.getConnection();
PreparedStatement ps = connection.prepareStatement(query)) {
ps.setString(1, apiUuid);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
status = rs.getString("SUB_VALIDATION");
}
}
} catch (SQLException e) {
handleException("Error while retrieving subscription validation status for API: " + apiUuid, e);
}
return status;
}

/**
* Persist revoked jwt signatures to database.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.api.SubscriptionAlreadyExistingException;
import org.wso2.carbon.apimgt.api.dto.ConditionDTO;
import org.wso2.carbon.apimgt.api.dto.ConditionGroupDTO;
import org.wso2.carbon.apimgt.api.model.OperationPolicy;
Expand Down Expand Up @@ -57,10 +58,13 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import static org.wso2.carbon.apimgt.impl.APIConstants.POLICY_ENABLED_FOR_ANALYTICS;
Expand Down Expand Up @@ -1565,4 +1569,94 @@ public List<API> getAllApisByLabel(String gatewayLabel, Boolean expand) {
}
return apiList;
}

public String getApplicationSubscriber(String uuid) throws APIManagementException {
String subscriber = "";
String query = SQLConstants.GET_APPLICATION_BY_UUID_SQL;
try (Connection connection = APIMgtDBUtil.getConnection()) {
try (PreparedStatement ps = connection.prepareStatement(query)) {
ps.setString(1, uuid);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
subscriber = rs.getString("USER_ID");
}
}
}
} catch (SQLException e) {
throw new APIManagementException("Error while getting subscriber info", e);
}
return subscriber;
}

public Map<String, Object> subscribeToAPI(int apiId, int appId, String tier, String subscriber)
throws APIManagementException {
Map<String, Object> subscriptionDetails = new HashMap<>();
int subscriptionId = -1;
String subscriptionUUID = UUID.randomUUID().toString();

String checkDuplicateQuery = SQLConstants.CHECK_EXISTING_SUBSCRIPTION_API_SQL;
String sqlQuery = SQLConstants.ADD_SUBSCRIPTION_SQL;

try (Connection connection = APIMgtDBUtil.getConnection()) {
connection.setAutoCommit(false);
try (PreparedStatement ps = connection.prepareStatement(checkDuplicateQuery)) {
ps.setInt(1, apiId);
ps.setInt(2, appId);
try (ResultSet resultSet = ps.executeQuery()) {
//If the subscription already exists
if (resultSet.next()) {
String subStatus = resultSet.getString("SUB_STATUS");
String subCreationStatus = resultSet.getString("SUBS_CREATE_STATE");
if ((APIConstants.SubscriptionStatus.UNBLOCKED.equals(subStatus) ||
APIConstants.SubscriptionStatus.ON_HOLD.equals(subStatus) ||
APIConstants.SubscriptionStatus.REJECTED.equals(subStatus)) &&
APIConstants.SubscriptionCreatedStatus.SUBSCRIBE.equals(subCreationStatus)) {

throw new SubscriptionAlreadyExistingException(
String.format("Subscription already exists for API/API Prouct %s in Application %s",
apiId, appId));
}
}
}
}

String subscriptionIDColumn = "SUBSCRIPTION_ID";
if (connection.getMetaData().getDriverName().contains("PostgreSQL")) {
subscriptionIDColumn = "subscription_id";
}
try (PreparedStatement preparedStForInsert = connection.prepareStatement(sqlQuery,
new String[]{subscriptionIDColumn})) {
preparedStForInsert.setString(1, tier);
preparedStForInsert.setString(10, tier);
preparedStForInsert.setInt(2, apiId);
preparedStForInsert.setInt(3, appId);
preparedStForInsert.setString(4, APIConstants.SubscriptionStatus.UNBLOCKED);
preparedStForInsert.setString(5, APIConstants.SubscriptionCreatedStatus.SUBSCRIBE);
preparedStForInsert.setString(6, subscriber);

Timestamp timestamp = new Timestamp(System.currentTimeMillis());
preparedStForInsert.setTimestamp(7, timestamp);
preparedStForInsert.setTimestamp(8, timestamp);
preparedStForInsert.setString(9, subscriptionUUID);

preparedStForInsert.executeUpdate();
try (ResultSet rs = preparedStForInsert.getGeneratedKeys()) {
while (rs.next()) {
subscriptionId = Integer.parseInt(rs.getString(1));
}
connection.commit();
} catch (SQLException e) {
connection.rollback();
throw new APIManagementException("Error while adding subscription for API/API Product " + apiId +
" in Application " + appId, e);
}
}
} catch (SQLException e) {
throw new APIManagementException("Error while adding subscription for API/API Product " + apiId +
" in Application " + appId, e);
}
subscriptionDetails.put("id", subscriptionId);
subscriptionDetails.put("uuid", subscriptionUUID);
return subscriptionDetails;
}
}
Loading

0 comments on commit 3754885

Please sign in to comment.