diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java index bd20ce915dab..c92b685edafa 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java @@ -36,6 +36,7 @@ import org.wso2.carbon.apimgt.api.model.KeyManagerApplicationInfo; import org.wso2.carbon.apimgt.api.model.Monetization; import org.wso2.carbon.apimgt.api.model.OAuthApplicationInfo; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.api.model.ResourceFile; import org.wso2.carbon.apimgt.api.model.Scope; import org.wso2.carbon.apimgt.api.model.SubscribedAPI; @@ -461,12 +462,13 @@ OAuthApplicationInfo updateAuthClient(String userId, Application application, * @param offset * @param groupingId the groupId to which the applications must belong. * @param organization Identifier of an organization + * @param sharedOrganization * @return Applications * @throws APIManagementException if failed to applications for given subscriber */ Application[] getApplicationsWithPagination(Subscriber subscriber, String groupingId, int start, int offset, - String search, String sortColumn, String sortOrder, String organization) + String search, String sortColumn, String sortOrder, String organization, String sharedOrganization) throws APIManagementException; /** @@ -891,4 +893,26 @@ boolean isKeyManagerByNameAllowedForUser(String keyManagerName, String organizat * @throws APIManagementException */ boolean removalKeys(Application application, String keyMappingId, String xWSO2Tenant) throws APIManagementException; + + /** + * @param searchQuery search query. ex : provider:admin + * @param organizationInfo Identifier of an organization + * @param start starting number + * @param end ending number + * @return + * @throws APIManagementException + */ + Map searchPaginatedAPIs(String searchQuery, OrganizationInfo organizationInfo, int start, int end, + String sortBy, String sortOrder) throws APIManagementException; + + /** + * @param searchQuery search query + * @param organizationInfo Information about the organization + * @param start + * @param end + * @return + * @throws APIManagementException + */ + Map searchPaginatedContent(String searchQuery, OrganizationInfo organizationInfo, int start, int end) + throws APIManagementException; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java index 80068b537543..5259f06a9d4d 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java @@ -100,6 +100,7 @@ public enum ExceptionCodes implements ErrorHandler { INVALID_CONTEXT(900346, "Invalid context provided", 400, "Invalid context provided for API: %s:%s"), INVALID_ENDPOINT_URL(900346, "Endpoint URL(s) is(are) not valid", 400, "Endpoint URL(s) is(are) not valid"), USER_ROLES_CANNOT_BE_NULL(900610, "Access control roles cannot be empty", 400, "Access control roles cannot be empty when visibility is restricted"), + ORGS_CANNOT_BE_NULL(900610, "Access control organizatoins cannot be empty", 400, "Access control organizations cannot be empty when visibility is restricted"), API_REVISION_NOT_FOUND(900347, "API Revision Not Found", 404, "Requested API Revision with id %s not found"), EXISTING_API_REVISION_DEPLOYMENT_FOUND(900348, "Can not delete API Revision ", 400, "Couldn't delete API revision since API revision is currently deployed to a gateway. " + "You need to undeploy the API Revision from the gateway before attempting deleting API Revision: %s "), diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/dto/KeyManagerConfigurationDTO.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/dto/KeyManagerConfigurationDTO.java index f1a61252290b..295f07b3fb8e 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/dto/KeyManagerConfigurationDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/dto/KeyManagerConfigurationDTO.java @@ -19,7 +19,9 @@ package org.wso2.carbon.apimgt.api.dto; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -44,6 +46,7 @@ public class KeyManagerConfigurationDTO implements Serializable { private String alias = null; private KeyManagerPermissionConfigurationDTO permissions = new KeyManagerPermissionConfigurationDTO(); private Boolean isUsed = null; + private List allowedOrganizations = new ArrayList(); public KeyManagerConfigurationDTO() { } @@ -62,6 +65,7 @@ public KeyManagerConfigurationDTO(KeyManagerConfigurationDTO keyManagerConfigura this.externalReferenceId = keyManagerConfigurationDTO.getExternalReferenceId(); this.endpoints = keyManagerConfigurationDTO.getEndpoints(); this.setPermissions(keyManagerConfigurationDTO.getPermissions()); + this.allowedOrganizations = keyManagerConfigurationDTO.getAllowedOrganizations(); } public String getName() { @@ -207,4 +211,12 @@ public void setUsed(Boolean isUsed) { this.isUsed = isUsed; } + + public List getAllowedOrganizations() { + return allowedOrganizations; + } + + public void setAllowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/API.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/API.java index a7d852eff7e1..216f1e79e4c4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/API.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/API.java @@ -102,8 +102,10 @@ public class API implements Serializable { private String visibility; private String visibleRoles; private String visibleTenants; + private String visibleOrganizations; - private boolean endpointSecured = false; + + private boolean endpointSecured = false; private boolean endpointAuthDigest = false; private String endpointUTUsername; private String endpointUTPassword; @@ -1561,6 +1563,14 @@ public List getApiPolicies() { public void setApiPolicies(List apiPolicies) { this.apiPolicies = apiPolicies; } + + public String getVisibleOrganizations() { + return visibleOrganizations; + } + + public void setVisibleOrganizations(String visibleOrganizations) { + this.visibleOrganizations = visibleOrganizations; + } /** * Property to hold whether the API isEGRESS (1) diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/Application.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/Application.java index 556746ea27c9..e40003eeb9fe 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/Application.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/Application.java @@ -58,6 +58,8 @@ public Map> getKeyManagerWiseOAuthApp( private String keyType; private int subscriptionCount; private String keyManager; + private String sharedOrganization; + public String getCreatedTime() { return createdTime; } @@ -320,4 +322,12 @@ public void setOrganization(String organization) { this.organization = organization; } + + public String getSharedOrganization() { + return sharedOrganization; + } + + public void setSharedOrganization(String sharedOrganization) { + this.sharedOrganization = sharedOrganization; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/OrganizationInfo.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/OrganizationInfo.java new file mode 100644 index 000000000000..ba05a3a9705a --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/OrganizationInfo.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, WSO2 LLc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.api.model; + +public class OrganizationInfo { + + + String superOrganization; + String name; + String id; + String organizationSelector; + OrganizationInfo parentOrganization; + OrganizationInfo[] childOrganizations; + + public String getSuperOrganization() { + return superOrganization; + } + public void setSuperOrganization(String superOrganization) { + this.superOrganization = superOrganization; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public OrganizationInfo getParentOrganization() { + return parentOrganization; + } + public void setParentOrganization(OrganizationInfo parentOrganization) { + this.parentOrganization = parentOrganization; + } + public OrganizationInfo[] getChildOrganizations() { + return childOrganizations; + } + public void setChildOrganizations(OrganizationInfo[] childOrganizations) { + this.childOrganizations = childOrganizations; + } + public String getOrganizationSelector() { + return organizationSelector; + } + public void setOrganizationSelector(String organizationSelector) { + this.organizationSelector = organizationSelector; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/policy/SubscriptionPolicy.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/policy/SubscriptionPolicy.java index 481308c21d01..32c4b046d4cb 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/policy/SubscriptionPolicy.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/policy/SubscriptionPolicy.java @@ -18,8 +18,10 @@ package org.wso2.carbon.apimgt.api.model.policy; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; public class SubscriptionPolicy extends Policy { @@ -34,6 +36,7 @@ public class SubscriptionPolicy extends Policy { private String tierQuotaType; private int graphQLMaxDepth; private int graphQLMaxComplexity; + private List allowedOrganizations = new ArrayList(); public SubscriptionPolicy(String name) { super(name); @@ -122,11 +125,11 @@ public void setGraphQLMaxComplexity(int graphQLMaxComplexity) { @Override public String toString() { return "SubscriptionPolicy [rateLimitCount=" + rateLimitCount + ", rateLimitTimeUnit=" + rateLimitTimeUnit - + ", customAttributes=" + Arrays.toString(customAttributes) + ", stopOnQuotaReach=" + stopOnQuotaReach - + ", billingPlan=" + billingPlan + ", monetizationPlan=" + monetizationPlan - + ", monetizationPlanProperties=" + monetizationPlanProperties + ", tierQuotaType=" + tierQuotaType - + ", maxDepth=" + graphQLMaxDepth + ", maxComplexity=" + graphQLMaxComplexity - + ", subscriberCount= " + subscriberCount + "]"; + + ", subscriberCount=" + subscriberCount + ", customAttributes=" + Arrays.toString(customAttributes) + + ", stopOnQuotaReach=" + stopOnQuotaReach + ", billingPlan=" + billingPlan + ", monetizationPlan=" + + monetizationPlan + ", monetizationPlanProperties=" + monetizationPlanProperties + ", tierQuotaType=" + + tierQuotaType + ", graphQLMaxDepth=" + graphQLMaxDepth + ", graphQLMaxComplexity=" + + graphQLMaxComplexity + ", allowedOrganizations=" + allowedOrganizations + "]"; } public int getSubscriberCount() { @@ -136,4 +139,12 @@ public int getSubscriberCount() { public void setSubscriberCount(int subscriberCount) { this.subscriberCount = subscriberCount; } + + public List getAllowedOrganizations() { + return allowedOrganizations; + } + + public void setAllowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediator.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediator.java index f1d344c0ecbf..68e6752fe175 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediator.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediator.java @@ -60,12 +60,17 @@ public boolean mediate(MessageContext messageContext) { String issuer = authContext.getIssuer(); List scopes = authContext.getRequestTokenScopes(); if (StringUtils.isNotBlank(issuer)) { - KeyManagerDto keyManagerDto = KeyManagerHolder.getKeyManagerByIssuer(tenantDomain, issuer); - if (keyManagerDto != null && StringUtils.isNotBlank(scope) && scopes.contains(scope)) { - String token = authContext.getAccessToken(); - String consumerKey = authContext.getConsumerKey(); - oneTimeTokenExecutorService.execute(() -> - keyManagerDto.getKeyManager().revokeOneTimeToken(token, consumerKey)); + List keyManagerDtoList = KeyManagerHolder.getKeyManagerByIssuer(tenantDomain, issuer); + if (keyManagerDtoList != null) { + KeyManagerDto keyManagerDto = keyManagerDtoList.get(0); // TODO : Does not support multiple km with same + // issuer + + if (keyManagerDto != null && StringUtils.isNotBlank(scope) && scopes.contains(scope)) { + String token = authContext.getAccessToken(); + String consumerKey = authContext.getConsumerKey(); + oneTimeTokenExecutorService.execute(() -> + keyManagerDto.getKeyManager().revokeOneTimeToken(token, consumerKey)); + } } } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediatorTest.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediatorTest.java index 470e0d5e572e..d22a8e09980b 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediatorTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/mediators/OneTimeTokenRevocationMediatorTest.java @@ -72,8 +72,10 @@ public void init() { Mockito.when(authContext.getIssuer()).thenReturn("https://localhost:9443/oauth2/token"); Mockito.when(authContext.getRequestTokenScopes()).thenReturn(scopes); + List keymanagerList = new ArrayList(); + keymanagerList.add(keyManagerDto); Mockito.when(KeyManagerHolder.getKeyManagerByIssuer(Mockito.anyString(), Mockito.anyString())). - thenReturn(keyManagerDto); + thenReturn(keymanagerList); Mockito.when(keyManagerDto.getKeyManager()).thenReturn(keyManager); Mockito.doNothing().when(oneTimeExecutorService).execute(() -> keyManagerDto.getKeyManager().revokeOneTimeToken(Mockito.anyString(), Mockito.anyString())); @@ -115,7 +117,7 @@ public void testMediateWithNullIssuer() { * KeyManagerDto is set to null */ @Test - public void testMediateWithNullKeyManagerDto() { + public void testMediateWithNullKeyManagerDtoList() { Mockito.when(KeyManagerHolder.getKeyManagerByIssuer(Mockito.anyString(), Mockito.anyString())). thenReturn(null); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml index 80f54c38e631..943694c7f83f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml @@ -646,6 +646,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java index 781edede2efd..341a27d85877 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java @@ -221,6 +221,7 @@ public final class APIConstants { public static final String VISIBILITY = "visibility"; public static final String API_RESTRICTED_VISIBILITY = "restricted"; + public static final String API_RESTRICTED_BY_ORG = "restricted_by_org"; public static final String API_PRIVATE_VISIBILITY = "private"; @@ -844,6 +845,7 @@ private Permissions() { "internal_application_mgt_delete", "internal_application_mgt_update", "internal_application_mgt_view", "internal_user_mgt_list"}; public static final String KEY_MANAGER_CLIENT_APPLICATION_PREFIX = "wso2_apim_km_"; + public static final String DEFAULT_APP_SHARING_KEYWORD = "private"; public static final String TOKEN_URL = "TokenURL"; public static final String REVOKE_URL = "RevokeURL"; @@ -2020,6 +2022,8 @@ public enum RegistryResourceTypesForUI { public static final String API_POLICY_API_LEVEL = "apiLevel"; public static final String BILLING_PLAN_FREE = "FREE"; + public static final String ALLOWED_ORGANIZATIONS_DEFAULT = "ALL"; + public static final String DEFAULT_VISIBLE_ORG = "all"; public static final String POLICY_RESET = "reset"; public static final String BLOCKING_EVENT_TYPE = "wso2event"; @@ -3251,6 +3255,13 @@ public static class TokenValidationConstants { public static final String TOKEN_VALIDATION_CONFIG = "TokenValidation"; public static final String ENFORCE_JWT_TYPE_HEADER_VALIDATION = "EnforceTypeHeaderValidation"; } + + // For Organization access control Configuration + public static final String ORG_BASED_ACCESS_CONTROL = "OrganizationBasedAccessControl"; + public static final String ORG_BASED_ACCESS_CONTROL_ENABLE = "Enable"; + public static final String ORG_BASED_ACCESS_CONTROL_ORG_NAME_CLAIM = "OrganizationNameLocalClaim"; + public static final String ORG_BASED_ACCESS_CONTROL_ORG_ID_CLAIM = "OrganizationIDLocalClaim"; + public static final String ORG_BASED_ACCESS_CONTROL_SELECTOR_CLAIM = "OrgaizationSelectorLocalClaim"; public static class TransactionCounter { diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java index 24c4c60ba85e..3c28f9654c22 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java @@ -76,6 +76,7 @@ import org.wso2.carbon.apimgt.api.model.Monetization; import org.wso2.carbon.apimgt.api.model.OAuthAppRequest; import org.wso2.carbon.apimgt.api.model.OAuthApplicationInfo; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.api.model.ResourceFile; import org.wso2.carbon.apimgt.api.model.Scope; import org.wso2.carbon.apimgt.api.model.SubscribedAPI; @@ -1665,6 +1666,9 @@ public int addApplication(Application application, String userId, String organiz if (StringUtils.isBlank(application.getCallbackUrl())) { application.setCallbackUrl(null); } + if (StringUtils.isEmpty(application.getSharedOrganization())) { + application.setSharedOrganization(APIConstants.DEFAULT_APP_SHARING_KEYWORD); + } int applicationId = apiMgtDAO.addApplication(application, userId, organization); Application createdApplication = apiMgtDAO.getApplicationById(applicationId); @@ -1895,6 +1899,9 @@ public void updateApplication(Application application) throws APIManagementExcep application.setApplicationAttributes(null); } validateApplicationPolicy(application, existingApp.getOrganization()); + if (StringUtils.isEmpty(application.getSharedOrganization())) { + application.setSharedOrganization(APIConstants.DEFAULT_APP_SHARING_KEYWORD); + } apiMgtDAO.updateApplication(application); Application updatedApplication = apiMgtDAO.getApplicationById(application.getId()); if (log.isDebugEnabled()) { @@ -2787,19 +2794,20 @@ public String[] getGroupIds(String response) throws APIManagementException { * @param sortColumn The sort column. * @param sortOrder The sort order. * @param organization Identifier of an Organization + * @param sharedOrganization * @return Application[] The Applications. * @throws APIManagementException */ @Override public Application[] getApplicationsWithPagination(Subscriber subscriber, String groupingId, int start, int offset - , String search, String sortColumn, String sortOrder, String organization) + , String search, String sortColumn, String sortOrder, String organization, String sharedOrganization) throws APIManagementException { if (APIUtil.isOnPremResolver()) { organization = tenantDomain; } return apiMgtDAO.getApplicationsWithPagination(subscriber, groupingId, start, offset, - search, sortColumn, sortOrder, organization); + search, sortColumn, sortOrder, organization, sharedOrganization); } /** @@ -3840,16 +3848,36 @@ public void changeUserPassword(String currentPassword, String newPassword) throw @Override public Map searchPaginatedAPIs(String searchQuery, String organization, int start, int end, String sortBy, String sortOrder) throws APIManagementException { - - Map result = new HashMap(); - if (log.isDebugEnabled()) { - log.debug("Original search query received : " + searchQuery); - } + Organization org = new Organization(organization); String userName = (userNameWithoutChange != null) ? userNameWithoutChange : username; String[] roles = APIUtil.getListOfRoles(userName); Map properties = APIUtil.getUserProperties(userName); UserContext userCtx = new UserContext(userNameWithoutChange, org, properties, roles); + + return searchPaginatedAPIs(searchQuery, start, end, org, userCtx); + } + + @Override + public Map searchPaginatedAPIs(String searchQuery, OrganizationInfo organizationInfo, int start, int end, + String sortBy, String sortOrder) throws APIManagementException { + Organization org = new Organization(organizationInfo.getSuperOrganization()); + String userName = (userNameWithoutChange != null) ? userNameWithoutChange : username; + String[] roles = APIUtil.getListOfRoles(userName); + Map properties = APIUtil.getUserProperties(userName); + UserContext userCtx = new UserContext(userNameWithoutChange, + new Organization(organizationInfo.getOrganizationSelector()), properties, roles); + + return searchPaginatedAPIs(searchQuery, start, end, org, userCtx); + } + + private Map searchPaginatedAPIs(String searchQuery, int start, int end, Organization org, + UserContext userCtx) throws APIManagementException { + Map result = new HashMap(); + if (log.isDebugEnabled()) { + log.debug("Original search query received : " + searchQuery); + } + try { DevPortalAPISearchResult searchAPIs = apiPersistenceInstance.searchAPIsForDevPortal(org, searchQuery, start, end, userCtx); @@ -3895,7 +3923,7 @@ public Map searchPaginatedAPIs(String searchQuery, String organi throw new APIManagementException("Error while searching the api ", e); } return result; - } + } @Override public ApiTypeWrapper getAPIorAPIProductByUUID(String uuid, String organization) throws APIManagementException { @@ -4006,6 +4034,7 @@ private API addTiersToAPI(API api, String organization) throws APIManagementExce int tenantId = APIUtil.getInternalIdFromTenantDomainOrOrganization(organization); Set tierNames = api.getAvailableTiers(); + apiMgtDAO.getSubscriptionPolicies(tenantId); Map definedTiers = APIUtil.getTiers(tenantId); Set availableTiers = new HashSet(); @@ -4194,6 +4223,31 @@ public API getLightweightAPI(APIIdentifier identifier, String orgId) throws APIM public Map searchPaginatedContent(String searchQuery, String organization, int start, int end) throws APIManagementException { + String userame = (userNameWithoutChange != null) ? userNameWithoutChange : username; + Organization org = new Organization(organization); + Map properties = APIUtil.getUserProperties(userame); + String[] roles = APIUtil.getFilteredUserRoles(userame); + ; + UserContext ctx = new UserContext(userame, org, properties, roles); + return searchPaginatedContent(org, searchQuery, start, end, ctx); + } + + @Override + public Map searchPaginatedContent(String searchQuery, OrganizationInfo organizationInfo, + int start, int end) throws APIManagementException { + + String userName = (userNameWithoutChange != null) ? userNameWithoutChange : username; + Organization org = new Organization(organizationInfo.getSuperOrganization()); + Map properties = APIUtil.getUserProperties(userName); + String[] roles = APIUtil.getFilteredUserRoles(userName); + + UserContext ctx = new UserContext(userName, new Organization(organizationInfo.getOrganizationSelector()), + properties, roles); + return searchPaginatedContent(org, searchQuery, start, end, ctx); + } + + private Map searchPaginatedContent(Organization org, String searchQuery, int start, int end, + UserContext ctx) throws APIManagementException { ArrayList compoundResult = new ArrayList(); Map docMap = new HashMap(); Map result = new HashMap(); @@ -4202,13 +4256,6 @@ public Map searchPaginatedContent(String searchQuery, String org List defSearchList = new ArrayList<>(); int totalLength = 0; - String userame = (userNameWithoutChange != null) ? userNameWithoutChange : username; - Organization org = new Organization(organization); - Map properties = APIUtil.getUserProperties(userame); - String[] roles = APIUtil.getFilteredUserRoles(userame); - ; - UserContext ctx = new UserContext(userame, org, properties, roles); - try { DevPortalContentSearchResult sResults = apiPersistenceInstance.searchContentForDevPortal(org, searchQuery, start, end, ctx); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java index 0c7e6d4e9e30..55f0b8c8d8f9 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java @@ -44,6 +44,7 @@ import org.wso2.carbon.apimgt.impl.dto.ExtendedJWTConfigurationDto; import org.wso2.carbon.apimgt.impl.dto.GatewayArtifactSynchronizerProperties; import org.wso2.carbon.apimgt.impl.dto.GatewayCleanupSkipList; +import org.wso2.carbon.apimgt.impl.dto.OrgAccessControl; import org.wso2.carbon.apimgt.impl.dto.RedisConfig; import org.wso2.carbon.apimgt.impl.dto.ThrottleProperties; import org.wso2.carbon.apimgt.impl.dto.TokenValidationDto; @@ -133,6 +134,15 @@ public class APIManagerConfiguration { private static String certificateBoundAccessEnabled; private GatewayCleanupSkipList gatewayCleanupSkipList = new GatewayCleanupSkipList(); private RedisConfig redisConfig = new RedisConfig(); + private OrgAccessControl orgAccessControl = new OrgAccessControl(); + public OrgAccessControl getOrgAccessControl() { + return orgAccessControl; + } + + public void setOrgAccessControl(OrgAccessControl orgAccessControl) { + this.orgAccessControl = orgAccessControl; + } + private Map> restApiJWTAuthAudiences = new HashMap<>(); private JSONObject subscriberAttributes = new JSONObject(); private static Map analyticsMaskProps; @@ -667,6 +677,8 @@ private void readChildElements(OMElement serverConfig, setAiConfiguration(element); } else if (APIConstants.TokenValidationConstants.TOKEN_VALIDATION_CONFIG.equals(localName)) { setTokenValidation(element); + } else if (APIConstants.ORG_BASED_ACCESS_CONTROL.equals(localName)) { + setOrgBasedAccessControlConfigs(element); } else if (APIConstants.HASHING.equals(localName)) { setHashingAlgorithm(element); } else if (APIConstants.TransactionCounter.TRANSACTIONCOUNTER.equals(localName)) { @@ -680,6 +692,30 @@ private void readChildElements(OMElement serverConfig, } } + private void setOrgBasedAccessControlConfigs(OMElement element) { + OMElement orgEnableElement = + element.getFirstChildWithName(new QName(APIConstants.ORG_BASED_ACCESS_CONTROL_ENABLE)); + if (orgEnableElement != null) { + orgAccessControl.setEnabled(Boolean.parseBoolean(orgEnableElement.getText())); + } + + OMElement orgSelectorElement = + element.getFirstChildWithName(new QName(APIConstants.ORG_BASED_ACCESS_CONTROL_SELECTOR_CLAIM)); + if (orgSelectorElement != null) { + orgAccessControl.setOrgSelectorClaim(orgSelectorElement.getText()); + } + OMElement orgNameElement = + element.getFirstChildWithName(new QName(APIConstants.ORG_BASED_ACCESS_CONTROL_ORG_NAME_CLAIM)); + if (orgNameElement != null) { + orgAccessControl.setOrgNameLocalClaim(orgNameElement.getText());; + } + OMElement orgIdElement = + element.getFirstChildWithName(new QName(APIConstants.ORG_BASED_ACCESS_CONTROL_ORG_ID_CLAIM)); + if (orgIdElement != null) { + orgAccessControl.setOrgIdLocalClaim(orgIdElement.getText()); + } + } + public boolean getTransactionCounterProperties() { return isTransactionCounterEnabled; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/ThrottlePolicyConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/ThrottlePolicyConstants.java index ebef1dbf2558..a7a7a3b1552c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/ThrottlePolicyConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/ThrottlePolicyConstants.java @@ -131,4 +131,6 @@ public class ThrottlePolicyConstants { public static final String COLUMN_MAX_DEPTH = "MAX_DEPTH"; public static final String COLUMN_MAX_COMPLEXITY = "MAX_COMPLEXITY"; + + public static final String COLUMN_ALLOWED_ORGANIZATIONS = "ALLOWED_ORGANIZATIONS"; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java index 8964e338e4b6..7a7c245992fd 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java @@ -3499,6 +3499,7 @@ public int addApplication(Application application, String userId, Connection con ps.setString(11, application.getUUID()); ps.setString(12, String.valueOf(application.getTokenType())); ps.setString(13, organization); + ps.setString(14, application.getSharedOrganization()); ps.executeUpdate(); rs = ps.getGeneratedKeys(); @@ -3539,7 +3540,8 @@ public void updateApplication(Application application) throws APIManagementExcep ps.setString(5, null); ps.setTimestamp(6, new Timestamp(System.currentTimeMillis())); ps.setString(7, application.getTokenType()); - ps.setInt(8, application.getId()); + ps.setString(8, application.getSharedOrganization()); + ps.setInt(9, application.getId()); ps.executeUpdate(); @@ -4120,7 +4122,8 @@ public boolean updateApplicationOwner(String userName, Application application) * @throws APIManagementException */ public Application[] getApplicationsWithPagination(Subscriber subscriber, String groupingId, int start, - int offset, String search, String sortColumn, String sortOrder, String organization) + int offset, String search, String sortColumn, String sortOrder, String organization, + String sharedOrganization) throws APIManagementException { Connection connection = null; @@ -4128,7 +4131,7 @@ public Application[] getApplicationsWithPagination(Subscriber subscriber, String ResultSet rs = null; Application[] applications = null; String sqlQuery = null; - + boolean isOrgSharingEnabled = true; //TODO need to come from config or from user info if (groupingId != null && !"null".equals(groupingId) && !groupingId.isEmpty()) { if (multiGroupAppSharingEnabled) { if (forceCaseInsensitiveComparisons) { @@ -4149,9 +4152,19 @@ public Application[] getApplicationsWithPagination(Subscriber subscriber, String } } else { if (forceCaseInsensitiveComparisons) { - sqlQuery = SQLConstantManagerFactory.getSQlString("GET_APPLICATIONS_PREFIX_NONE_CASESENSITVE"); + if (isOrgSharingEnabled) { + sqlQuery = SQLConstantManagerFactory + .getSQlString("GET_APPLICATIONS_PREFIX_NONE_CASESENSITVE_WITH_ORGSHARING"); + } else { + sqlQuery = SQLConstantManagerFactory.getSQlString("GET_APPLICATIONS_PREFIX_NONE_CASESENSITVE"); + } } else { - sqlQuery = SQLConstantManagerFactory.getSQlString("GET_APPLICATIONS_PREFIX_CASESENSITVE"); + if (isOrgSharingEnabled) { + sqlQuery = SQLConstantManagerFactory + .getSQlString("GET_APPLICATIONS_PREFIX_CASESENSITVE_WITH_ORGSHARING"); + } else { + sqlQuery = SQLConstantManagerFactory.getSQlString("GET_APPLICATIONS_PREFIX_CASESENSITVE"); + } } } @@ -4198,12 +4211,22 @@ public Application[] getApplicationsWithPagination(Subscriber subscriber, String prepStmt.setInt(6, offset); } } else { - prepStmt = connection.prepareStatement(sqlQuery); - prepStmt.setString(1, subscriber.getName()); - prepStmt.setString(2, organization); - prepStmt.setString(3, "%" + search + "%"); - prepStmt.setInt(4, start); - prepStmt.setInt(5, offset); + if (isOrgSharingEnabled) { + prepStmt = connection.prepareStatement(sqlQuery); + prepStmt.setString(1, subscriber.getName()); + prepStmt.setString(2, sharedOrganization); + prepStmt.setString(3, organization); + prepStmt.setString(4, "%" + search + "%"); + prepStmt.setInt(5, start); + prepStmt.setInt(6, offset); + } else { + prepStmt = connection.prepareStatement(sqlQuery); + prepStmt.setString(1, subscriber.getName()); + prepStmt.setString(2, organization); + prepStmt.setString(3, "%" + search + "%"); + prepStmt.setInt(4, start); + prepStmt.setInt(5, offset); + } } if (log.isDebugEnabled()) { log.debug("Query: " + sqlQuery); @@ -4240,6 +4263,7 @@ public Application[] getApplicationsWithPagination(Subscriber subscriber, String // Get custom attributes of application Map applicationAttributes = getApplicationAttributes(connection, applicationId); application.setApplicationAttributes(applicationAttributes); + application.setSharedOrganization(rs.getString("SHARED_ORGANIZATION")); applicationsList.add(application); } @@ -6692,6 +6716,7 @@ public Application getApplicationByUUID(String uuid) throws APIManagementExcepti application.setTokenType(rs.getString("TOKEN_TYPE")); application.setOwner(rs.getString("CREATED_BY")); application.setOrganization(rs.getString("ORGANIZATION")); + application.setSharedOrganization(rs.getString("SHARED_ORGANIZATION")); subscriber.setId(rs.getInt("SUBSCRIBER_ID")); application.setLastUpdatedTime(String.valueOf(rs.getTimestamp("UPDATED_TIME").getTime())); application.setCreatedTime(String.valueOf(rs.getTimestamp("CREATED_TIME").getTime())); @@ -9474,6 +9499,7 @@ public List getKeyManagerConfigurationsByOrganizatio log.error("Error while converting configurations in " + uuid, e); } keyManagerConfigurationDTO.setPermissions(getKeyManagerPermissions(keyManagerConfigurationDTO.getUuid())); + keyManagerConfigurationDTO.setAllowedOrganizations(getKeymanagerVisibleOrgs(uuid)); keyManagerConfigurationDTOS.add(keyManagerConfigurationDTO); } } @@ -9513,6 +9539,7 @@ public KeyManagerConfigurationDTO getKeyManagerConfigurationByID(String organiza keyManagerConfigurationDTO.setAdditionalProperties(map); } keyManagerConfigurationDTO.setPermissions(getKeyManagerPermissions(keyManagerConfigurationDTO.getUuid())); + keyManagerConfigurationDTO.setAllowedOrganizations(getKeymanagerVisibleOrgs(uuid)); return keyManagerConfigurationDTO; } } @@ -9584,6 +9611,7 @@ private KeyManagerConfigurationDTO getKeyManagerConfigurationByName(Connection c keyManagerConfigurationDTO.setAdditionalProperties(map); } keyManagerConfigurationDTO.setPermissions(getKeyManagerPermissions(uuid)); + keyManagerConfigurationDTO.setAllowedOrganizations(getKeymanagerVisibleOrgs(uuid)); return keyManagerConfigurationDTO; } } @@ -9626,6 +9654,7 @@ private KeyManagerConfigurationDTO getKeyManagerConfigurationByUUID(Connection c keyManagerConfigurationDTO.setAdditionalProperties(map); } keyManagerConfigurationDTO.setPermissions(getKeyManagerPermissions(uuid)); + keyManagerConfigurationDTO.setAllowedOrganizations(getKeymanagerVisibleOrgs(uuid)); return keyManagerConfigurationDTO; } } @@ -9666,6 +9695,18 @@ public void addKeyManagerConfiguration(KeyManagerConfigurationDTO keyManagerConf addPermissionStatement.executeBatch(); } } + List allowedOrgs = keyManagerConfigurationDTO.getAllowedOrganizations(); + if (allowedOrgs != null && !allowedOrgs.isEmpty()) { + try (PreparedStatement addVisibleOrgsStatement = conn.prepareStatement( + SQLConstants.KeyManagerOrgVisibilitySqlConstants.ADD_KEY_MANAGER_ORG_VISIBILITY_SQL)) { + for (String org : allowedOrgs) { + addVisibleOrgsStatement.setString(1, keyManagerConfigurationDTO.getUuid()); + addVisibleOrgsStatement.setString(2, org); + addVisibleOrgsStatement.addBatch(); + } + addVisibleOrgsStatement.executeBatch(); + } + } conn.commit(); } catch (SQLException e) { conn.rollback(); @@ -9746,6 +9787,23 @@ public void updateKeyManagerConfiguration(KeyManagerConfigurationDTO keyManagerC addPermissionStatement.executeBatch(); } } + try (PreparedStatement deleteOrgStatement = conn.prepareStatement(SQLConstants + .KeyManagerOrgVisibilitySqlConstants.DELETE_ALL_KEY_MANAGER_ORG_VISIBILITY_SQL)) { + deleteOrgStatement.setString(1, keyManagerConfigurationDTO.getUuid()); + deleteOrgStatement.executeUpdate(); + } + List allowedOrgs = keyManagerConfigurationDTO.getAllowedOrganizations(); + if (allowedOrgs != null && !allowedOrgs.isEmpty()) { + try (PreparedStatement addVisibleOrgsStatement = conn.prepareStatement( + SQLConstants.KeyManagerOrgVisibilitySqlConstants.ADD_KEY_MANAGER_ORG_VISIBILITY_SQL)) { + for (String org : allowedOrgs) { + addVisibleOrgsStatement.setString(1, keyManagerConfigurationDTO.getUuid()); + addVisibleOrgsStatement.setString(2, org); + addVisibleOrgsStatement.addBatch(); + } + addVisibleOrgsStatement.executeBatch(); + } + } conn.commit(); } catch (SQLException e) { conn.rollback(); @@ -9818,6 +9876,30 @@ public KeyManagerPermissionConfigurationDTO getKeyManagerPermissions(String keyM } return keyManagerPermissions; } + + public List getKeymanagerVisibleOrgs(String keyManagerUUID) throws APIManagementException { + List orgList = new ArrayList(); + try (Connection conn = APIMgtDBUtil.getConnection()) { + try { + String getKeyManagerPermissionQuery = SQLConstants.KeyManagerOrgVisibilitySqlConstants.GET_KEY_MANAGER_ORG_VISIBILITY_SQL; + PreparedStatement ps = conn.prepareStatement(getKeyManagerPermissionQuery); + ps.setString(1, keyManagerUUID); + ResultSet resultSet = ps.executeQuery(); + while (resultSet.next()) { + orgList.add(resultSet.getString("ALLOWED_ORGANIZATIONS")); + } + } catch (SQLException e) { + conn.rollback(); + handleException("Failed to get Key Manager organizations information for Key Manager " + keyManagerUUID, + e); + } + } catch (SQLException e) { + throw new APIManagementException( + "Error while retrieving key manager organizations with id " + keyManagerUUID, e); + } + return orgList; + } + public List getKeyManagerConfigurations() throws APIManagementException { List keyManagerConfigurationDTOS = new ArrayList<>(); @@ -9845,6 +9927,7 @@ public List getKeyManagerConfigurations() throws API log.error("Error while converting configurations in " + uuid, e); } keyManagerConfigurationDTO.setPermissions(getKeyManagerPermissions(uuid)); + keyManagerConfigurationDTO.setAllowedOrganizations(getKeymanagerVisibleOrgs(uuid)); keyManagerConfigurationDTOS.add(keyManagerConfigurationDTO); } } @@ -11728,6 +11811,19 @@ public void addSubscriptionPolicy(SubscriptionPolicy policy) throws APIManagemen policy.getMonetizationPlanProperties().get(APIConstants.Monetization.CURRENCY)); policyStatement.setInt(26, policy.getSubscriberCount()); } + + List allowedOrgs = policy.getAllowedOrganizations(); + if (allowedOrgs != null && !allowedOrgs.isEmpty()) { + try (PreparedStatement addVisibleOrgsStatement = conn + .prepareStatement(SQLConstants.PolicyOrgVisibilitySqlConstants.ADD_POLICY_ORG_VISIBILITY_SQL)) { + for (String org : allowedOrgs) { + addVisibleOrgsStatement.setString(1, policy.getUUID()); + addVisibleOrgsStatement.setString(2, org); + addVisibleOrgsStatement.addBatch(); + } + addVisibleOrgsStatement.executeBatch(); + } + } policyStatement.executeUpdate(); conn.commit(); } catch (SQLIntegrityConstraintViolationException e) { @@ -12441,6 +12537,7 @@ public SubscriptionPolicy[] getSubscriptionPolicies(int tenantID) throws APIMana monetizationPlanProperties.put(APIConstants.Monetization.CURRENCY, rs.getString(ThrottlePolicyConstants.COLUMN_CURRENCY)); subPolicy.setMonetizationPlanProperties(monetizationPlanProperties); + subPolicy.setAllowedOrganizations(getPolicyVisibleOrgs(subPolicy.getUUID())); InputStream binary = rs.getBinaryStream(ThrottlePolicyConstants.COLUMN_CUSTOM_ATTRIB); if (binary != null) { byte[] customAttrib = APIUtil.toByteArray(binary); @@ -12868,6 +12965,7 @@ public SubscriptionPolicy getSubscriptionPolicy(String policyName, int tenantId) policy.setGraphQLMaxDepth(resultSet.getInt(ThrottlePolicyConstants.COLUMN_MAX_DEPTH)); policy.setGraphQLMaxComplexity(resultSet.getInt(ThrottlePolicyConstants.COLUMN_MAX_COMPLEXITY)); policy.setSubscriberCount(resultSet.getInt(ThrottlePolicyConstants.COLUMN_CONNECTION_COUNT)); + policy.setAllowedOrganizations(getPolicyVisibleOrgs(policy.getUUID())); InputStream binary = resultSet.getBinaryStream(ThrottlePolicyConstants.COLUMN_CUSTOM_ATTRIB); if (binary != null) { byte[] customAttrib = APIUtil.toByteArray(binary); @@ -12920,6 +13018,8 @@ public SubscriptionPolicy getSubscriptionPolicyByUUID(String uuid) throws APIMan policy.setGraphQLMaxDepth(resultSet.getInt(ThrottlePolicyConstants.COLUMN_MAX_DEPTH)); policy.setGraphQLMaxComplexity(resultSet.getInt(ThrottlePolicyConstants.COLUMN_MAX_COMPLEXITY)); policy.setSubscriberCount(resultSet.getInt(ThrottlePolicyConstants.COLUMN_CONNECTION_COUNT)); + policy.setAllowedOrganizations(getPolicyVisibleOrgs(policy.getUUID())); + InputStream binary = resultSet.getBinaryStream(ThrottlePolicyConstants.COLUMN_CUSTOM_ATTRIB); if (binary != null) { byte[] customAttrib = APIUtil.toByteArray(binary); @@ -12949,6 +13049,29 @@ public SubscriptionPolicy getSubscriptionPolicyByUUID(String uuid) throws APIMan } return policy; } + + public List getPolicyVisibleOrgs(String policyUUID) throws APIManagementException { + List orgList = new ArrayList(); + try (Connection conn = APIMgtDBUtil.getConnection()) { + try { + String getPolicyPermissionQuery = SQLConstants.PolicyOrgVisibilitySqlConstants.GET_POLICY_ORG_VISIBILITY_SQL; + PreparedStatement ps = conn.prepareStatement(getPolicyPermissionQuery); + ps.setString(1, policyUUID); + ResultSet resultSet = ps.executeQuery(); + while (resultSet.next()) { + orgList.add(resultSet.getString(ThrottlePolicyConstants.COLUMN_ALLOWED_ORGANIZATIONS)); + } + } catch (SQLException e) { + conn.rollback(); + handleException("Failed to get policy allowed organizations " + policyUUID, + e); + } + } catch (SQLException e) { + throw new APIManagementException( + "Error while retrieving policy organizations with id " + policyUUID, e); + } + return orgList; + } /** * Retrieves list of pipelines for the policy with policy Id: policyId @@ -13434,6 +13557,24 @@ public void updateSubscriptionPolicy(SubscriptionPolicy policy) throws APIManage } } updateStatement.executeUpdate(); + + try (PreparedStatement deleteOrgsStatement = connection.prepareStatement(SQLConstants + .PolicyOrgVisibilitySqlConstants.DELETE_ALL_POLICY_ORG_VISIBILITY_SQL)) { + deleteOrgsStatement.setString(1, policy.getUUID()); + deleteOrgsStatement.executeUpdate(); + } + List allowedOrgs = policy.getAllowedOrganizations(); + if (allowedOrgs != null && !allowedOrgs.isEmpty()) { + try (PreparedStatement addOrgsStatement = connection.prepareStatement(SQLConstants + .PolicyOrgVisibilitySqlConstants.ADD_POLICY_ORG_VISIBILITY_SQL)) { + for (String org : allowedOrgs) { + addOrgsStatement.setString(1, policy.getUUID()); + addOrgsStatement.setString(2, org); + addOrgsStatement.addBatch(); + } + addOrgsStatement.executeBatch(); + } + } connection.commit(); } catch (SQLException e) { if (connection != null) { @@ -13653,7 +13794,9 @@ private void setCommonParametersForPolicy(PreparedStatement policyStatement, Pol if (!StringUtils.isBlank(policy.getUUID())) { policyStatement.setString(11, policy.getUUID()); } else { - policyStatement.setString(11, UUID.randomUUID().toString()); + String uuid = UUID.randomUUID().toString(); + policy.setUUID(uuid); + policyStatement.setString(11, uuid); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java index bdad6d440205..13bd5c628263 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java @@ -1013,8 +1013,8 @@ public class SQLConstants { public static final String APP_APPLICATION_SQL = " INSERT INTO AM_APPLICATION (NAME, SUBSCRIBER_ID, APPLICATION_TIER, " + " CALLBACK_URL, DESCRIPTION, APPLICATION_STATUS, GROUP_ID, CREATED_BY, CREATED_TIME, UPDATED_TIME, " + - "UUID, TOKEN_TYPE, ORGANIZATION)" + - " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"; + "UUID, TOKEN_TYPE, ORGANIZATION, SHARED_ORGANIZATION)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; public static final String UPDATE_APPLICATION_SQL = " UPDATE " + @@ -1026,7 +1026,8 @@ public class SQLConstants { " DESCRIPTION = ?, " + " UPDATED_BY = ?, " + " UPDATED_TIME = ?, " + - " TOKEN_TYPE = ? " + + " TOKEN_TYPE = ?, " + + " SHARED_ORGANIZATION = ? " + " WHERE" + " APPLICATION_ID = ?"; @@ -1634,6 +1635,7 @@ public class SQLConstants { " APP.TOKEN_TYPE," + " APP.CREATED_BY," + " APP.ORGANIZATION ORGANIZATION,"+ + " APP.SHARED_ORGANIZATION AS SHARED_ORGANIZATION, " + " SUB.USER_ID " + " FROM " + " AM_SUBSCRIBER SUB," + @@ -3846,6 +3848,40 @@ public static class KeyManagerPermissionsSqlConstants { " WHERE KEY_MANAGER_UUID = ?"; } + /** + * Static class to hold database queries related to AM_KEY_MANAGER_PERMISSIONS table + */ + public static class KeyManagerOrgVisibilitySqlConstants { + + public static final String ADD_KEY_MANAGER_ORG_VISIBILITY_SQL = + " INSERT INTO" + + " AM_KEY_MANAGER_ALLOWED_ORGS (KEY_MANAGER_UUID, ALLOWED_ORGANIZATIONS)" + + " VALUES(?, ?)"; + + public static final String DELETE_ALL_KEY_MANAGER_ORG_VISIBILITY_SQL = "DELETE FROM AM_KEY_MANAGER_ALLOWED_ORGS" + + " WHERE KEY_MANAGER_UUID = ?"; + + public static final String GET_KEY_MANAGER_ORG_VISIBILITY_SQL = + "SELECT ALLOWED_ORGANIZATIONS" + + " FROM AM_KEY_MANAGER_ALLOWED_ORGS " + + " WHERE KEY_MANAGER_UUID = ?"; + } + + public static class PolicyOrgVisibilitySqlConstants { + + public static final String ADD_POLICY_ORG_VISIBILITY_SQL = + " INSERT INTO" + + " AM_POLICY_ALLOWED_ORGS (POLICY_UUID, ALLOWED_ORGANIZATIONS)" + + " VALUES(?, ?)"; + + public static final String DELETE_ALL_POLICY_ORG_VISIBILITY_SQL = "DELETE FROM AM_POLICY_ALLOWED_ORGS" + + " WHERE POLICY_UUID = ?"; + + public static final String GET_POLICY_ORG_VISIBILITY_SQL = + "SELECT ALLOWED_ORGANIZATIONS" + + " FROM AM_POLICY_ALLOWED_ORGS " + + " WHERE POLICY_UUID = ?"; + } /** * Static class to hold database queries related to AM_TENANT_THEMES table */ diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstantsH2MySQL.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstantsH2MySQL.java index 3565c0ae4498..59ff88cc00b2 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstantsH2MySQL.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstantsH2MySQL.java @@ -181,7 +181,8 @@ public class SQLConstantsH2MySQL extends SQLConstants{ " GROUP_ID, " + " UUID, " + " APP.CREATED_BY AS CREATED_BY, " + - " APP.TOKEN_TYPE AS TOKEN_TYPE " + + " APP.TOKEN_TYPE AS TOKEN_TYPE, " + + " APP.SHARED_ORGANIZATION AS SHARED_ORGANIZATION " + " FROM" + " AM_APPLICATION APP, " + " AM_SUBSCRIBER SUB " + @@ -212,7 +213,8 @@ public class SQLConstantsH2MySQL extends SQLConstants{ " GROUP_ID, " + " UUID, " + " APP.CREATED_BY AS CREATED_BY, " + - " APP.TOKEN_TYPE AS TOKEN_TYPE " + + " APP.TOKEN_TYPE AS TOKEN_TYPE, " + + " APP.SHARED_ORGANIZATION AS SHARED_ORGANIZATION " + " FROM" + " AM_APPLICATION APP, " + " AM_SUBSCRIBER SUB " + @@ -227,6 +229,68 @@ public class SQLConstantsH2MySQL extends SQLConstants{ " )x left join AM_BLOCK_CONDITIONS bl on ( bl.TYPE = 'APPLICATION' AND bl.BLOCK_CONDITION = concat(concat(x.USER_ID,':'),x.name)) " + " ORDER BY $1 $2 limit ? , ?"; + public static final String GET_APPLICATIONS_PREFIX_CASESENSITVE_WITH_ORGSHARING = + "select distinct x.*,bl.ENABLED from (" + + "SELECT " + + " APPLICATION_ID, " + + " NAME," + + " APPLICATION_TIER," + + " APP.SUBSCRIBER_ID, " + + " APP.CREATED_TIME AS APP_CREATED_TIME, " + + " APP.UPDATED_TIME AS APP_UPDATED_TIME, " + + " CALLBACK_URL, " + + " DESCRIPTION, " + + " APPLICATION_STATUS, " + + " USER_ID, " + + " GROUP_ID, " + + " UUID, " + + " APP.CREATED_BY AS CREATED_BY, " + + " APP.TOKEN_TYPE AS TOKEN_TYPE, " + + " APP.SHARED_ORGANIZATION AS SHARED_ORGANIZATION " + + " FROM" + + " AM_APPLICATION APP, " + + " AM_SUBSCRIBER SUB " + + " WHERE " + + " SUB.SUBSCRIBER_ID = APP.SUBSCRIBER_ID " + + " AND (LOWER(SUB.USER_ID) = LOWER(?) OR APP.SHARED_ORGANIZATION = ? )" + + " AND " + + " APP.ORGANIZATION = ? " + + " And "+ + " LOWER (NAME) like LOWER (?)"+ + " )x left join AM_BLOCK_CONDITIONS bl on ( bl.TYPE = 'APPLICATION' AND bl.BLOCK_CONDITION = concat(concat(x.USER_ID,':'),x.name)) " + + " ORDER BY $1 $2 limit ? , ?"; + + public static final String GET_APPLICATIONS_PREFIX_NONE_CASESENSITVE_WITH_ORGSHARING = + "select distinct x.*,bl.ENABLED from (" + + "SELECT " + + " APPLICATION_ID, " + + " NAME," + + " APPLICATION_TIER," + + " APP.SUBSCRIBER_ID, " + + " APP.CREATED_TIME AS APP_CREATED_TIME, " + + " APP.UPDATED_TIME AS APP_UPDATED_TIME, " + + " CALLBACK_URL, " + + " DESCRIPTION, " + + " APPLICATION_STATUS, " + + " USER_ID, " + + " GROUP_ID, " + + " UUID, " + + " APP.CREATED_BY AS CREATED_BY, " + + " APP.TOKEN_TYPE AS TOKEN_TYPE, " + + " APP.SHARED_ORGANIZATION AS SHARED_ORGANIZATION " + + " FROM" + + " AM_APPLICATION APP, " + + " AM_SUBSCRIBER SUB " + + " WHERE " + + " SUB.SUBSCRIBER_ID = APP.SUBSCRIBER_ID " + + " AND (LOWER(SUB.USER_ID) = LOWER(?) OR APP.SHARED_ORGANIZATION = ? )" + + " AND " + + " APP.ORGANIZATION = ? " + + " And "+ + " LOWER (NAME) like LOWER (?)"+ + " )x left join AM_BLOCK_CONDITIONS bl on ( bl.TYPE = 'APPLICATION' AND bl.BLOCK_CONDITION = concat(concat(x.USER_ID,':'),x.name)) " + + " ORDER BY $1 $2 limit ? , ?"; + public static final String GET_APPLICATIONS_BY_TENANT_ID = " SELECT " + diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/OrgAccessControl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/OrgAccessControl.java new file mode 100644 index 000000000000..3c24445940e9 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/OrgAccessControl.java @@ -0,0 +1,50 @@ +/* + * 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.dto; + +public class OrgAccessControl { + private boolean isEnabled; + private String orgNameLocalClaim; + private String orgIdLocalClaim; + private String orgselectorClaim; + public boolean isEnabled() { + return isEnabled; + } + public void setEnabled(boolean isEnabled) { + this.isEnabled = isEnabled; + } + public String getOrgNameLocalClaim() { + return orgNameLocalClaim; + } + public void setOrgNameLocalClaim(String orgNameLocalClaim) { + this.orgNameLocalClaim = orgNameLocalClaim; + } + public String getOrgIdLocalClaim() { + return orgIdLocalClaim; + } + public void setOrgIdLocalClaim(String orgIdLocalClaim) { + this.orgIdLocalClaim = orgIdLocalClaim; + } + public String getOrgSelectorClaim() { + return orgselectorClaim; + } + public void setOrgSelectorClaim(String orgselectorClaim) { + this.orgselectorClaim = orgselectorClaim; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/OrganizationKeyManagerDto.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/OrganizationKeyManagerDto.java index 83fff9803992..df279f62ea9c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/OrganizationKeyManagerDto.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/OrganizationKeyManagerDto.java @@ -21,14 +21,16 @@ import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.jwt.JWTValidator; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; public class OrganizationKeyManagerDto { private Map keyManagerMap = new LinkedHashMap<>(); - private Map issuerNameMap = new HashMap<>(); + private Map> issuerNameMap = new HashMap<>(); public Map getKeyManagerMap() { @@ -51,23 +53,27 @@ public void putKeyManagerDto(KeyManagerDto keyManagerDto) { } else { keyManagerMap.put(keyManagerDto.getName(), keyManagerDto); } - issuerNameMap.put(keyManagerDto.getIssuer(), keyManagerDto.getName()); + issuerNameMap.computeIfAbsent(keyManagerDto.getIssuer(), k -> new ArrayList<>()).add(keyManagerDto.getName()); + } public void removeKeyManagerDtoByName(String name) { KeyManagerDto keyManagerDto = keyManagerMap.get(name); if (keyManagerDto != null) { - issuerNameMap.remove(keyManagerDto.getIssuer()); + issuerNameMap.get(keyManagerDto.getIssuer()).remove(name); + if (issuerNameMap.get(keyManagerDto.getIssuer()).isEmpty()) { + issuerNameMap.remove(keyManagerDto.getIssuer()); + } } keyManagerMap.remove(name); } public JWTValidator getJWTValidatorByIssuer(String issuer) { - String keyManagerName = issuerNameMap.get(issuer); - if (StringUtils.isNotEmpty(keyManagerName)) { - KeyManagerDto keyManagerDto = keyManagerMap.get(keyManagerName); + List keyManagerNames = issuerNameMap.get(issuer); + if (keyManagerNames != null && !keyManagerNames.isEmpty()) { + KeyManagerDto keyManagerDto = keyManagerMap.get(keyManagerNames.get(0)); if (keyManagerDto != null) { return keyManagerDto.getJwtValidator(); } @@ -75,11 +81,15 @@ public JWTValidator getJWTValidatorByIssuer(String issuer) { return null; } - public KeyManagerDto getKeyManagerDtoByIssuer(String issuer) { + public List getKeyManagerDtoByIssuer(String issuer) { - String keyManagerName = issuerNameMap.get(issuer); - if (StringUtils.isNotEmpty(keyManagerName)) { - return keyManagerMap.get(keyManagerName); + List dtoList = new ArrayList(); + List keyManagerNames = issuerNameMap.get(issuer); + if (keyManagerNames != null && !keyManagerNames.isEmpty()) { + for (String keyManagerName : keyManagerNames) { + dtoList.add(keyManagerMap.get(keyManagerName)); + } + return dtoList; } return null; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/factory/KeyManagerHolder.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/factory/KeyManagerHolder.java index b5ec7ff146b6..5e6cfc9bcbdf 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/factory/KeyManagerHolder.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/factory/KeyManagerHolder.java @@ -42,6 +42,7 @@ import org.wso2.carbon.apimgt.impl.utils.APIUtil; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -259,10 +260,12 @@ public static KeyManager getKeyManagerInstance(String tenantDomain, String keyMa return keyManager; } - public static KeyManagerDto getKeyManagerByIssuer(String tenantDomain, String issuer) { + public static List getKeyManagerByIssuer(String tenantDomain, String issuer) { if (globalJWTValidatorMap.containsKey(issuer)) { - return globalJWTValidatorMap.get(issuer); + List list = new ArrayList(); + list.add(globalJWTValidatorMap.get(issuer)); + return list; } OrganizationKeyManagerDto organizationKeyManagerDto = getTenantKeyManagerDto(tenantDomain); if (organizationKeyManagerDto != null) { diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/jwt/JWTValidationServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/jwt/JWTValidationServiceImpl.java index a4cd18dcb1f5..52eecbb825c8 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/jwt/JWTValidationServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/jwt/JWTValidationServiceImpl.java @@ -18,6 +18,8 @@ package org.wso2.carbon.apimgt.impl.jwt; +import java.util.List; + import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -39,7 +41,18 @@ public JWTValidationInfo validateJWTToken(SignedJWTInfo signedJWTInfo) throws AP JWTValidationInfo jwtValidationInfo = new JWTValidationInfo(); String issuer = signedJWTInfo.getJwtClaimsSet().getIssuer(); if (StringUtils.isNotEmpty(issuer)) { - KeyManagerDto keyManagerDto = KeyManagerHolder.getKeyManagerByIssuer(tenantDomain, issuer); + List keyManagerDtoList = KeyManagerHolder.getKeyManagerByIssuer(tenantDomain, issuer); + KeyManagerDto keyManagerDto = null; + if (keyManagerDtoList.size() == 1) { // only one keymanager. no need to check if it can handle token + keyManagerDto = keyManagerDtoList.get(0); + } else { + for (KeyManagerDto kmrDto : keyManagerDtoList) { + if (kmrDto.getKeyManager().canHandleToken(signedJWTInfo.getToken())) { + keyManagerDto = kmrDto; + break; + } + } + } if (keyManagerDto != null && keyManagerDto.getJwtValidator() != null) { JWTValidationInfo validationInfo = keyManagerDto.getJwtValidator().validateToken(signedJWTInfo); validationInfo.setKeyManager(keyManagerDto.getName()); @@ -56,7 +69,18 @@ public String getKeyManagerNameIfJwtValidatorExist(SignedJWTInfo signedJWTInfo) String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); String issuer = signedJWTInfo.getJwtClaimsSet().getIssuer(); - KeyManagerDto keyManagerDto = KeyManagerHolder.getKeyManagerByIssuer(tenantDomain, issuer); + List keyManagerDtoList = KeyManagerHolder.getKeyManagerByIssuer(tenantDomain, issuer); + KeyManagerDto keyManagerDto = null; + if (keyManagerDtoList.size() == 1) { // only one keymanager. no need to check if it can handle token + keyManagerDto = keyManagerDtoList.get(0); + } else { + for (KeyManagerDto kmrDto : keyManagerDtoList) { + if (kmrDto.getKeyManager().canHandleToken(signedJWTInfo.getToken())) { + keyManagerDto = kmrDto; + break; + } + } + } if (keyManagerDto != null && keyManagerDto.getJwtValidator() != null) { return keyManagerDto.getName(); }else{ diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java index fde4b5f08aea..8898126bb16d 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java @@ -10027,6 +10027,15 @@ public static ExternalEnvironment getExternalEnvironment(String providerName) { return ServiceReferenceHolder.getInstance().getExternalEnvironment(providerName); } + /** + * Get org access control enabled status + * + * @return true or false + */ + public static boolean isOrganizationAccessControlEnabled() { + return ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService().getAPIManagerConfiguration() + .getOrgAccessControl().isEnabled(); + } /** * Get registered API Definition Parsers as a Map * @@ -10829,7 +10838,24 @@ public static List getPaginatedApplicationList( } return applications.subList(offset, endIndex); } - + + public static Set getAllowedTiersForTheOrganization(Set tiers, String organization, + String superOrganization) throws APIManagementException { + int tenantId = APIUtil.getInternalIdFromTenantDomainOrOrganization(superOrganization); + SubscriptionPolicy[] policies = ApiMgtDAO.getInstance().getSubscriptionPolicies(tenantId); + Set allowedTiers = new HashSet(); + for (Tier tier : tiers) { + for (SubscriptionPolicy policy : policies) { + if (policy.getPolicyName().equals(tier.getName()) + && (policy.getAllowedOrganizations().isEmpty() + || policy.getAllowedOrganizations().contains(organization))) { + allowedTiers.add(tier); + } + } + } + return allowedTiers; + } + public static String getAPIMVersion() { return CarbonUtils.getServerConfiguration().getFirstProperty("Version"); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIConsumerImplTest.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIConsumerImplTest.java index 79123abe8256..17180850614c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIConsumerImplTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIConsumerImplTest.java @@ -530,13 +530,14 @@ public void testUpdateAuthClient() throws APIManagementException { public void testGetApplicationsWithPagination() throws APIManagementException { Application[] applications = new Application[] { new Application(1), new Application(2) }; Mockito.when(apiMgtDAO - .getApplicationsWithPagination((Subscriber) Mockito.any(), Mockito.anyString(), Mockito.anyInt(), + .getApplicationsWithPagination(Mockito.any(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), - Mockito.anyString())).thenReturn(applications); + Mockito.anyString(), Mockito.anyString())).thenReturn(applications); APIConsumerImpl apiConsumer = new APIConsumerImplWrapper(apiMgtDAO); Assert.assertEquals( apiConsumer.getApplicationsWithPagination(new Subscriber("sub1"), "1", 0, 5, - "", "", "ASC", "testorg").length, 2); + "", "", "ASC", "testorg", + "sharedOrg").length, 2); } @Test diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json b/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json index d81009e30f7b..bd13af9e0ef1 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json @@ -1525,8 +1525,8 @@ "type" : "string", "example" : "EXCHANGED", "description" : "The type of the tokens to be used (exchanged or without exchanged). Accepted values are EXCHANGED, DIRECT or BOTH.", - "default" : "DIRECT", - "enum" : [ "EXCHANGED", "DIRECT", "BOTH" ] + "enum" : [ "EXCHANGED", "DIRECT", "BOTH" ], + "default" : "DIRECT" } } }, diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java index 31726e4a75a6..903d2d8d9148 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java @@ -215,9 +215,11 @@ public static class Monetization { public static final String DISPLAY_PUBLISHER_ROLES = "display_publisher_roles"; public static final String ACCESS_CONTROL = "publisher_access_control"; public static final String NO_ACCESS_CONTROL = "all"; + public static final String VISIBLE_ORGANIZATIONS = "visible_organizations"; public static final String NULL_USER_ROLE_LIST = "null"; public static final String API_RESTRICTED_VISIBILITY = "restricted"; public static final String API_PRIVATE_VISIBILITY = "private"; + public static final String API_RESTRICTED_BY_ORG = "restricted_by_org"; public static final String API_CONTROLLED_VISIBILITY = "controlled"; public static final String DOC_OWNER_VISIBILITY = "OWNER_ONLY"; public static final String API_GLOBAL_VISIBILITY = "public"; @@ -405,4 +407,6 @@ public enum APITransportType { public static final String API_OVERVIEW_GATEWAY_VENDOR = "overview_gatewayVendor"; public static final String ASYNC_API_TRANSPORT_PROTOCOLS = "overview_asyncTransportProtocols"; + + public static final String DEFAULT_VISIBLE_ORG = "all"; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java index 52f799f742f9..0f3f8fb1f632 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java @@ -35,6 +35,7 @@ import org.wso2.carbon.apimgt.persistence.dto.*; import org.wso2.carbon.apimgt.persistence.dto.Documentation; import org.wso2.carbon.apimgt.persistence.dto.Mediation; +import org.wso2.carbon.apimgt.persistence.dto.Organization; import org.wso2.carbon.apimgt.persistence.dto.ResourceFile; import org.wso2.carbon.apimgt.persistence.dto.DocumentContent.ContentSourceType; import org.wso2.carbon.apimgt.persistence.exceptions.*; @@ -42,6 +43,7 @@ import org.wso2.carbon.apimgt.persistence.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.persistence.mapper.APIMapper; import org.wso2.carbon.apimgt.persistence.mapper.APIProductMapper; +import org.wso2.carbon.apimgt.persistence.utils.PersistenceUtil; import org.wso2.carbon.apimgt.persistence.utils.PublisherAPISearchResultComparator; import org.wso2.carbon.apimgt.persistence.utils.RegistryPersistenceDocUtil; import org.wso2.carbon.apimgt.persistence.utils.RegistryPersistenceUtil; @@ -52,7 +54,6 @@ import org.wso2.carbon.governance.api.exception.GovernanceException; import org.wso2.carbon.governance.api.generic.GenericArtifactManager; import org.wso2.carbon.governance.api.generic.dataobjects.GenericArtifact; -import org.wso2.carbon.governance.api.generic.dataobjects.GenericArtifactImpl; import org.wso2.carbon.governance.api.util.GovernanceUtils; import org.wso2.carbon.registry.common.ResourceData; import org.wso2.carbon.registry.common.TermData; @@ -171,10 +172,15 @@ public PublisherAPI addAPI(Organization org, PublisherAPI publisherAPI) throws A if (visibleRolesList != null) { visibleRoles = visibleRolesList.split(","); } + + String visibleOrgs = APIConstants.DEFAULT_VISIBLE_ORG; + if (!StringUtils.isEmpty(api.getVisibleOrganizations())) { + visibleOrgs = api.getVisibleOrganizations(); + } String publisherAccessControlRoles = api.getAccessControlRoles(); updateRegistryResources(registry, artifactPath, publisherAccessControlRoles, api.getAccessControl(), - api.getAdditionalProperties()); + api.getAdditionalProperties(), visibleOrgs); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, artifactPath, registry); @@ -190,6 +196,7 @@ public PublisherAPI addAPI(Organization org, PublisherAPI publisherAPI) throws A } resource.setContent(api.getSwaggerDefinition()); resource.setMediaType("application/json"); + resource.setProperty(APIConstants.VISIBLE_ORGANIZATIONS, visibleOrgs); registry.put(resourcePath, resource); //Need to set anonymous if the visibility is public RegistryPersistenceUtil.clearResourcePermissions(resourcePath, api.getId(), @@ -210,6 +217,7 @@ public PublisherAPI addAPI(Organization org, PublisherAPI publisherAPI) throws A } resource.setContent(api.getAsyncApiDefinition()); resource.setMediaType(APIConstants.APPLICATION_JSON_MEDIA_TYPE); //add a constant for app.json + resource.setProperty(APIConstants.VISIBLE_ORGANIZATIONS, visibleOrgs); registry.put(resourcePath, resource); RegistryPersistenceUtil.clearResourcePermissions(resourcePath, api.getId(), ((UserRegistry) registry).getTenantId()); @@ -224,6 +232,7 @@ public PublisherAPI addAPI(Organization org, PublisherAPI publisherAPI) throws A ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, docLocation); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, docLocation); registry.commitTransaction(); api.setUuid(artifact.getId()); @@ -548,8 +557,13 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw String[] visibleRoles = new String[0]; String publisherAccessControlRoles = api.getAccessControlRoles(); + String visibleOrgs = APIConstants.DEFAULT_VISIBLE_ORG; + if (!StringUtils.isEmpty(api.getVisibleOrganizations())) { + visibleOrgs = api.getVisibleOrganizations(); + } + updateRegistryResources(registry, artifactPath, publisherAccessControlRoles, api.getAccessControl(), - api.getAdditionalProperties()); + api.getAdditionalProperties(), visibleOrgs); //propagate api status change and access control roles change to document artifact String newStatus = updateApiArtifact.getAttribute(APIConstants.API_OVERVIEW_STATUS); @@ -594,6 +608,7 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, resourcePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, resourcePath); } // Update api def file permissions, required for API definition content search functionality @@ -607,6 +622,7 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, resourcePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, resourcePath); } } else if (api.isAsync()) { String resourcePath = RegistryPersistenceUtil.getOpenAPIDefinitionFilePath(api.getId().getName(), @@ -617,6 +633,7 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, resourcePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, resourcePath); } } else if (APIConstants.API_TYPE_SOAP.equals(api.getType())) { String resourcePath = RegistryPersistenceUtil.getOpenAPIDefinitionFilePath(api.getId().getName(), @@ -628,6 +645,7 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, resourcePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, resourcePath); } } @@ -663,6 +681,7 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw + doc.getName(); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, documentationPath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, documentationPath); if (Documentation.DocumentSourceType.INLINE.equals(doc.getSourceType()) || Documentation.DocumentSourceType.MARKDOWN.equals(doc.getSourceType())) { @@ -671,12 +690,14 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw + RegistryConstants.PATH_SEPARATOR + doc.getName(); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, contentPath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, contentPath); } else if (Documentation.DocumentSourceType.FILE.equals(doc.getSourceType()) && doc.getFilePath() != null) { String filePath = RegistryPersistenceDocUtil.getDocumentationFilePath(api.getId(), doc.getFilePath().split("files" + RegistryConstants.PATH_SEPARATOR)[1]); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), visibleRoles, filePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, filePath); } } } @@ -1123,8 +1144,15 @@ public DevPortalAPISearchResult searchAPIsForDevPortal(Organization org, String log.debug("Requested query for devportal search: " + searchQuery); String modifiedQuery = RegistrySearchUtil.getDevPortalSearchQuery(searchQuery, ctx, isAllowDisplayAPIsWithMultipleStatus(), isAllowDisplayAPIsWithMultipleVersions()); + if (!PersistenceUtil.isAdminUser(ctx)) { + String orgName = ctx.getOrganization().getName(); + if (orgName != null && orgName.contains(" ")) { + orgName = orgName.replace(" ", "+"); + } + modifiedQuery = modifiedQuery + "&visible_organizations=(" + APIConstants.DEFAULT_VISIBLE_ORG + " OR " + + orgName + ")"; + } log.debug("Modified query for devportal search: " + modifiedQuery); - String userNameLocal; if (holder.isAnonymousMode()) { userNameLocal = APIConstants.WSO2_ANONYMOUS_USER; @@ -1148,6 +1176,62 @@ public DevPortalAPISearchResult searchAPIsForDevPortal(Organization org, String } return result; } + + protected static List searchDevportalAPIs(String query, int tenantId, Registry reg, int start, int offset) + throws APIManagementException { + List artifacts = new ArrayList(); + query = query.replace("PUBLISHED", "published").replace("PROTOTYPED", "prototyped").replace("DEPRECATED", + "deprecated");// convert to lowercase + Map fields = RegistryPersistenceUtil.getFields(query); + //since store_view_roles and overview_visible_organizations are passed as property search value, remove this. + fields.remove("overview_store_view_roles"); + fields.remove("overview_visible_organizations"); + String filterQuery = RegistryPersistenceUtil.buildFQStringForProperties(query); + String modifiedQuery = "q=* TO *&" + filterQuery; + + try { + PaginationContext.init(start, offset, "ASC", APIConstants.API_OVERVIEW_NAME, getMaxPaginationLimit()); + UserRegistry systemUserRegistry = ServiceReferenceHolder.getInstance().getRegistryService() + .getRegistry(CarbonConstants.REGISTRY_SYSTEM_USERNAME, tenantId); + ContentBasedSearchService contentBasedSearchService = new ContentBasedSearchService(); + SearchResultsBean resultsBean; + if(StringUtils.isEmpty(filterQuery)) { + resultsBean = contentBasedSearchService.searchByAttribute(fields, systemUserRegistry); + } else { + resultsBean = contentBasedSearchService.searchByAttribute(modifiedQuery, fields, systemUserRegistry); + } + + if (log.isDebugEnabled()) { + log.debug("Search Result: " + resultsBean); + } + + ResourceData[] resourceDataList = resultsBean.getResourceDataList(); + int errorCount = 0; // We use this to check how many errors occurred. + for (ResourceData resourceData : resourceDataList) { + GovernanceArtifact governanceArtifact = null; + String path = resourceData.getResourcePath().substring(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH.length()); + try { + governanceArtifact = GovernanceUtils.retrieveGovernanceArtifactByPath(reg, path); + } catch (GovernanceException e) { + // We do not through any exception here. Only logging is done. + // We increase the error count for each error. If all the paths failed, then we throw an error + errorCount++; + log.error("Error occurred while retrieving governance artifact by path : " + path, e); + } + if (governanceArtifact != null) { + artifacts.add(governanceArtifact); + } + } + if (errorCount != 0 && errorCount == resourceDataList.length) { + // This means that all the paths have failed. So we throw an error. + throw new APIManagementException("Error occurred while retrieving all the governance artifacts"); + } + } catch (IndexerException | RegistryException e) { + String msg = "Failed to search APIs"; + throw new APIManagementException(msg, e); + } + return artifacts; + } private DevPortalAPISearchResult searchPaginatedDevPortalAPIs(Registry userRegistry, int tenantIDLocal, String searchQuery, int start, int offset) throws APIManagementException { @@ -1159,9 +1243,10 @@ private DevPortalAPISearchResult searchPaginatedDevPortalAPIs(Registry userRegis PaginationContext.init(start, offset, "ASC", APIConstants.API_OVERVIEW_NAME, maxPaginationLimit); log.debug("Dev portal list apis query " + searchQuery); - List governanceArtifacts = GovernanceUtils - .findGovernanceArtifacts(searchQuery, userRegistry, APIConstants.API_RXT_MEDIA_TYPE, - true); + //List governanceArtifacts = GovernanceUtils + // .findGovernanceArtifacts(searchQuery, userRegistry, APIConstants.API_RXT_MEDIA_TYPE, + // true); + List governanceArtifacts = searchDevportalAPIs(searchQuery, tenantIDLocal, userRegistry, start, offset); totalLength = PaginationContext.getInstance().getLength(); boolean isFound = true; if (governanceArtifacts == null || governanceArtifacts.size() == 0) { @@ -1885,6 +1970,8 @@ public void saveWSDL(Organization org, String apiId, ResourceFile wsdlResourceFi if (visibleRolesList != null) { visibleRoles = visibleRolesList.split(","); } + String visibleOrgs = getOrganizationVisibilityForApiArtifact(registry, apiId); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, wsdlResourcePath); RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRoles, wsdlResourcePath, registry); @@ -2037,6 +2124,8 @@ public void saveOASDefinition(Organization org, String apiId, String apiDefiniti // Need to set anonymous if the visibility is public RegistryPersistenceUtil.clearResourcePermissions(resourcePath, new APIIdentifier(apiProviderName, apiName, apiVersion), ((UserRegistry) registry).getTenantId()); + String visibleOrgs = getOrganizationVisibilityForApiArtifact(registry, apiId); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, resourcePath); RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRolesArr, resourcePath, registry); @@ -2137,7 +2226,8 @@ public void saveAsyncDefinition(Organization org, String apiId, String apiDefini ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRolesArr, resourcePath , registry); - + String visibleOrgs = getOrganizationVisibilityForApiArtifact(registry, apiId); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, resourcePath); } catch (RegistryException | APIPersistenceException | APIManagementException e) { throw new AsyncSpecPersistenceException("Error while adding AsyncApi Definition for " + apiId, e); } finally { @@ -2228,6 +2318,8 @@ public void saveGraphQLSchemaDefinition(Organization org, String apiId, String s ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.apiProvider, api.visibility, api.visibleRoles, saveResourcePath, registry); + String visibleOrgs = getOrganizationVisibilityForApiArtifact(registry, apiId); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, saveResourcePath); } catch (RegistryException | APIManagementException | APIPersistenceException e) { throw new GraphQLPersistenceException("Error while adding Graphql Definition for api " + apiId, e); @@ -2293,9 +2385,10 @@ public Documentation addDocumentation(Organization org, String apiId, Documentat GenericArtifactManager docArtifactManager = new GenericArtifactManager(registry, APIConstants.DOCUMENTATION_KEY); GenericArtifact docArtifact = docArtifactManager.newGovernanceArtifact(new QName(documentation.getName())); - docArtifactManager.addGenericArtifact(RegistryPersistenceDocUtil.createDocArtifactContent(docArtifact, - apiName, apiVersion, apiProviderName, documentation)); - + GenericArtifact genericDocArtifact = RegistryPersistenceDocUtil.createDocArtifactContent(docArtifact, + apiName, apiVersion, apiProviderName, documentation); + docArtifactManager.addGenericArtifact(genericDocArtifact); + String docArtifactPath = GovernanceUtils.getArtifactPath(registry, genericDocArtifact.getId()); String apiPath = RegistryPersistenceUtil.getAPIPath(apiName, apiVersion, apiProviderName); String docVisibility = documentation.getVisibility().name(); String[] authorizedRoles = RegistryPersistenceUtil.getAuthorizedRoles(apiPath, tenantDomain); @@ -2309,6 +2402,9 @@ public Documentation addDocumentation(Organization org, String apiId, Documentat visibility = APIConstants.DOC_OWNER_VISIBILITY; } } + //Get org visibility value + String visibleOrgs = getOrganizationVisibilityForApiArtifact(registry, apiId); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, docArtifactPath); RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, authorizedRoles, docArtifact .getPath(), registry); String docFilePath = docArtifact.getAttribute(APIConstants.DOC_FILE_PATH); @@ -2322,6 +2418,7 @@ public Documentation addDocumentation(Organization org, String apiId, Documentat String filePath = docFilePath.substring(startIndex, docFilePath.length()); RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, authorizedRoles, filePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, filePath); } } documentation.setId(docArtifact.getId()); @@ -2372,6 +2469,8 @@ public Documentation updateDocumentation(Organization org, String apiId, Documen visibility = APIConstants.DOC_OWNER_VISIBILITY; } } + // Get org visibility value + String visibleOrgs = getOrganizationVisibilityForApiArtifact(registry, apiId); GenericArtifact updateApiArtifact = RegistryPersistenceDocUtil.createDocArtifactContent(artifact, apiProviderName, apiName, apiVersion, documentation); @@ -2381,6 +2480,7 @@ public Documentation updateDocumentation(Organization org, String apiId, Documen RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, authorizedRoles, artifact.getPath(), registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, artifact.getPath()); String docFilePath = artifact.getAttribute(APIConstants.DOC_FILE_PATH); if (docFilePath != null && !"".equals(docFilePath)) { @@ -2393,6 +2493,7 @@ public Documentation updateDocumentation(Organization org, String apiId, Documen String filePath = docFilePath.substring(startIndex, docFilePath.length()); RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, authorizedRoles, filePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, filePath); } return documentation; } catch (RegistryException | APIManagementException | APIPersistenceException e) { @@ -2548,7 +2649,7 @@ public DocumentContent addDocumentationContent(Organization org, String apiId, S .getDocumentArtifactManager(registry); GenericArtifact docArtifact = docArtifactManager.getGenericArtifact(docId); Documentation doc = RegistryPersistenceDocUtil.getDocumentation(docArtifact); - + String visibleOrgs = getOrganizationVisibilityForApiArtifact(registry, apiId); if (DocumentContent.ContentSourceType.FILE.equals(content.getSourceType())) { ResourceFile resource = content.getResourceFile(); String filePath = RegistryPersistenceDocUtil.getDocumentFilePath(apiProviderName, apiName, apiVersion, @@ -2562,6 +2663,7 @@ public DocumentContent addDocumentationContent(Organization org, String apiId, S RegistryPersistenceUtil.setResourcePermissions( RegistryPersistenceUtil.replaceEmailDomain(apiProviderName), visibility, visibleRoles, filePath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, filePath); //documentation.setFilePath(addResourceFile(apiId, filePath, icon)); String savedFilePath = addResourceFile(filePath, resource, registry, tenantDomain); //doc.setFilePath(savedFilePath); @@ -2601,6 +2703,7 @@ public DocumentContent addDocumentationContent(Organization org, String apiId, S } RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, authorizedRoles, contentPath, registry); + updateOrgVisibilityValueInRegistryForArtifacts(visibleOrgs, registry, contentPath); GenericArtifact updateDocArtifact = RegistryPersistenceDocUtil.createDocArtifactContent(docArtifact, apiProviderName, apiName, apiVersion, doc); Boolean toggle = Boolean.parseBoolean(updateDocArtifact.getAttribute("toggle")); @@ -3041,7 +3144,7 @@ private void saveAPIStatus(Registry registry, String artifactId, String apiStatu * @throws RegistryException Registry Exception. */ private void updateRegistryResources(Registry registry, String artifactPath, String publisherAccessControlRoles, - String publisherAccessControl, Map additionalProperties) + String publisherAccessControl, Map additionalProperties, String visibleOrganizations) throws RegistryException { publisherAccessControlRoles = (publisherAccessControlRoles == null || publisherAccessControlRoles.trim() .isEmpty()) ? APIConstants.NULL_USER_ROLE_LIST : publisherAccessControlRoles; @@ -3074,6 +3177,10 @@ private void updateRegistryResources(Registry registry, String artifactPath, Str // the roles that were specified can be maintained. apiResource.setProperty(APIConstants.DISPLAY_PUBLISHER_ROLES, publisherAccessControlRoles); apiResource.setProperty(APIConstants.ACCESS_CONTROL, publisherAccessControl); + if (!StringUtils.isEmpty(visibleOrganizations) && visibleOrganizations.contains(" ")) { + visibleOrganizations = visibleOrganizations.replace(" ", "+"); + } + apiResource.setProperty(APIConstants.VISIBLE_ORGANIZATIONS, visibleOrganizations); apiResource.removeProperty(APIConstants.CUSTOM_API_INDEXER_PROPERTY); if (additionalProperties != null && additionalProperties.size() != 0) { for (Map.Entry entry : additionalProperties.entrySet()) { @@ -3085,7 +3192,28 @@ private void updateRegistryResources(Registry registry, String artifactPath, Str } } - protected int getMaxPaginationLimit() { + /** + * Adds the organization visibility value to api-artifact in the registry + * @param visibleOrgs Organization that the corresponding API should be visible to + * @param registry + * @param artifactResourcePath + * @throws RegistryException + */ + private void updateOrgVisibilityValueInRegistryForArtifacts(String visibleOrgs, Registry registry, + String artifactResourcePath) throws RegistryException { + if (registry.resourceExists(artifactResourcePath)) { + Resource artifactResource = registry.get(artifactResourcePath); + if (artifactResource != null) { + if (!StringUtils.isEmpty(visibleOrgs) && visibleOrgs.contains(" ")) { + visibleOrgs = visibleOrgs.replace(" ", "+"); + } + artifactResource.setProperty(APIConstants.VISIBLE_ORGANIZATIONS, visibleOrgs); + registry.put(artifactResourcePath, artifactResource); + } + } + } + + protected static int getMaxPaginationLimit() { return Integer.MAX_VALUE; } @@ -3329,8 +3457,13 @@ public PublisherAPIProduct addAPIProduct(Organization org, PublisherAPIProduct p } String publisherAccessControlRoles = apiProduct.getAccessControlRoles(); + String visibleOrgs = APIConstants.DEFAULT_VISIBLE_ORG; + // if (StringUtils.isEmpty(apiProduct.getVisibleOrganizations())) { + //visibleOrgs = apiProduct.getVisibleOrganizations(); + // TODO fix for products and do needful for unified search + // } updateRegistryResources(registry, artifactPath, publisherAccessControlRoles, apiProduct.getAccessControl(), - apiProduct.getAdditionalProperties()); + apiProduct.getAdditionalProperties(), visibleOrgs); RegistryPersistenceUtil.setResourcePermissions(apiProduct.getId().getProviderName(), apiProduct.getVisibility(), visibleRoles, artifactPath, registry); @@ -3555,8 +3688,13 @@ public PublisherAPIProduct updateAPIProduct(Organization org, PublisherAPIProduc applyTags(apiProduct.getTags(), registry, artifactPath); String publisherAccessControlRoles = apiProduct.getAccessControlRoles(); + String visibleOrgs = APIConstants.DEFAULT_VISIBLE_ORG; + // if (APIConstants.API_RESTRICTED_BY_ORG.equals(apiProduct.getVisibility())){ + //visibleOrgs = apiProduct.getVisibleOrganizations(); + // TODO fix for products and do needful for unified search + // } updateRegistryResources(registry, artifactPath, publisherAccessControlRoles, apiProduct.getAccessControl(), - apiProduct.getAdditionalProperties()); + apiProduct.getAdditionalProperties(), visibleOrgs); RegistryPersistenceUtil.setResourcePermissions(apiProduct.getId().getProviderName(), apiProduct.getVisibility(), visibleRoles, artifactPath, registry); registry.commitTransaction(); @@ -4199,4 +4337,17 @@ private void setAPITypeForSwagger(String resourcePath, int index, } } } + + private String getOrganizationVisibilityForApiArtifact(Registry registry, String apiId) throws RegistryException { + /*Get org visibility value*/ + String artifactPath = GovernanceUtils.getArtifactPath(registry, apiId); + //get API + Resource apiResource = registry.get(artifactPath); + //get orgs of the API + String visibleOrgs = apiResource.getProperty(APIConstants.VISIBLE_ORGANIZATIONS); + if (StringUtils.isEmpty(visibleOrgs)) { + visibleOrgs = APIConstants.DEFAULT_VISIBLE_ORG; + } + return visibleOrgs; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/DevPortalAPI.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/DevPortalAPI.java index 9db22f4078e0..a38331074dc5 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/DevPortalAPI.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/DevPortalAPI.java @@ -45,6 +45,7 @@ public class DevPortalAPI extends DevPortalAPIInfo { private String subscriptionAvailability; // need to decide isSubscriptionAvailable private String subscriptionAvailableOrgs; // (subscriptionAvailableTenants): need to decide the value of "isSubscriptionAvailable" + private String visibleOrganizations; //visible organizations private String authorizationHeader; private String apiKeyHeader; private List securityScheme = new ArrayList<>(); @@ -342,13 +343,20 @@ public void setGatewayVendor(String gatewayVendor) { this.gatewayVendor = gatewayVendor; } + public String getVisibleOrganizations() { + return visibleOrganizations; + } + + public void setVisibleOrganizations(String visibleOrganizations) { + this.visibleOrganizations = visibleOrganizations; + } + public String getAsyncTransportProtocols() { return asyncTransportProtocols; } public void setAsyncTransportProtocols(String asyncTransportProtocols) { this.asyncTransportProtocols = asyncTransportProtocols; } - @Override public String toString() { return "DevPortalAPI [status=" + status + ", isDefaultVersion=" + isDefaultVersion + ", description=" @@ -357,16 +365,17 @@ public String toString() { + businessOwnerEmail + ", transports=" + transports + ", redirectURL=" + redirectURL + ", apiExternalProductionEndpoint=" + apiExternalProductionEndpoint + ", apiExternalSandboxEndpoint=" + apiExternalSandboxEndpoint + ", apiOwner=" + apiOwner + ", advertiseOnly=" + advertiseOnly - + ", subscriptionAvailability=" + subscriptionAvailability + ", subscriptionAvailableOrgs=" - + subscriptionAvailableOrgs + ", authorizationHeader=" + authorizationHeader + ", securityScheme=" - + securityScheme + ", environments=" + environments + ", gatewayVendor=" + gatewayVendor - + ", asyncTransportProtocols=" + asyncTransportProtocols + ", apiCategories=" + apiCategories - + ", isMonetizationEnabled=" + isMonetizationEnabled + ", keyManagers=" + keyManagers - + ", deploymentEnvironments=" + deploymentEnvironments + ", tags=" + tags + ", additionalProperties=" - + additionalProperties + ", endpointConfig=" + endpointConfig + ", type=" + type + ", advertisedOnly=" - + advertisedOnly + ", swaggerDefinition=" + swaggerDefinition + ", contextTemplate=" + contextTemplate - + ", apiSecurity=" + apiSecurity + ", visibility=" + visibility + ", visibleRoles=" + visibleRoles - + "]"; + + ", vendor=" + vendor + ", subscriptionAvailability=" + subscriptionAvailability + + ", subscriptionAvailableOrgs=" + subscriptionAvailableOrgs + ", visibleOrganizations=" + + visibleOrganizations + ", authorizationHeader=" + authorizationHeader + ", apiKeyHeader=" + + apiKeyHeader + ", securityScheme=" + securityScheme + ", environments=" + environments + + ", apiCategories=" + apiCategories + ", isMonetizationEnabled=" + isMonetizationEnabled + + ", keyManagers=" + keyManagers + ", deploymentEnvironments=" + deploymentEnvironments + ", tags=" + + tags + ", additionalProperties=" + additionalProperties + ", endpointConfig=" + endpointConfig + + ", type=" + type + ", advertisedOnly=" + advertisedOnly + ", swaggerDefinition=" + swaggerDefinition + + ", contextTemplate=" + contextTemplate + ", apiSecurity=" + apiSecurity + ", visibility=" + visibility + + ", visibleRoles=" + visibleRoles + ", gatewayVendor=" + gatewayVendor + ", asyncTransportProtocols=" + + asyncTransportProtocols + "]"; } public String getApiSecurity() { diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/PublisherAPI.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/PublisherAPI.java index 1f5c98f6dbd8..fb3f51727431 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/PublisherAPI.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/PublisherAPI.java @@ -46,7 +46,8 @@ public class PublisherAPI extends PublisherAPIInfo { private String businessOwnerEmail; private String visibility; private String visibleRoles; - private String visibleOrganizations; //visibleTenants + private String visibleSuperOrganizations; //visibleTenants + private String visibleOrganizations; //visible organizations private boolean endpointSecured; private String swaggerDefinition; private String asyncApiDefinition; @@ -665,39 +666,48 @@ public String getVendor() { public void setVendor(String vendor) { this.vendor = vendor; } - - @Override - public String toString() { - return "PublisherAPI [isDefaultVersion=" + isDefaultVersion + ", description=" + description + ", wsdlUrl=" - + wsdlUrl + ", wadlUrl=" + wadlUrl + ", technicalOwner=" + technicalOwner + ", technicalOwnerEmail=" - + technicalOwnerEmail + ", businessOwner=" + businessOwner + ", businessOwnerEmail=" - + businessOwnerEmail + ", visibility=" + visibility + ", visibleRoles=" + visibleRoles - + ", visibleOrganizations=" + visibleOrganizations + ", endpointSecured=" + endpointSecured - + ", endpointAuthDigest=" + endpointAuthDigest + ", endpointUTUsername=" + endpointUTUsername - + ", endpointUTPassword=" + endpointUTPassword + ", transports=" + transports + ", inSequence=" - + inSequence + ", outSequence=" + outSequence + ", faultSequence=" + faultSequence + ", responseCache=" - + responseCache + ", cacheTimeout=" + cacheTimeout + ", endpointConfig=" + endpointConfig - + ", subscriptionAvailability=" + subscriptionAvailability + ", subscriptionAvailableOrgs=" - + subscriptionAvailableOrgs + ", implementation=" + implementation + ", productionMaxTps=" - + productionMaxTps + ", sandboxMaxTps=" + sandboxMaxTps + ", authorizationHeader=" + authorizationHeader - + ", apiKeyHeader=" + apiKeyHeader - + ", apiSecurity=" + apiSecurity + ", enableSchemaValidation=" + enableSchemaValidation - + ", enableSubscriberVerification=" + enableSubscriberVerification + ", enableStore=" + enableStore - + ", testKey=" + testKey + ", contextTemplate=" + contextTemplate + ", availableTierNames=" - + availableTierNames + ", environments=" + environments - + ", corsConfiguration=" + corsConfiguration + ", websubSubscriptionConfiguration=" - + websubSubscriptionConfiguration + ", apiCategories=" - + apiCategories + ", isMonetizationEnabled=" + isMonetizationEnabled + ", monetizationProperties=" - + monetizationProperties + ", keyManagers=" + keyManagers + ", deploymentEnvironments=" - + deploymentEnvironments + ", tags=" + tags + ", accessControl=" + accessControl + ", gatewayVendor=" - + gatewayVendor + ", asyncTransportProtocols=" + asyncTransportProtocols + ", accessControlRoles=" - + accessControlRoles + ", additionalProperties=" + additionalProperties - + ", thumbnail=" + thumbnail + ", createdTime=" + createdTime + ", lastUpdated=" + lastUpdated - + ", versionTimestamp=" + versionTimestamp + ",apiExternalProductionEndpoint=" - + apiExternalProductionEndpoint + ",apiExternalSandboxEndpoint=" + apiExternalSandboxEndpoint - + ", originalDevportalURL" + redirectURL + ", apiOwner" + apiOwner + ", vendor" + vendor - + ", toString()=" + super.toString() + "]"; - } + + public String getVisibleSuperOrganizations() { + return visibleSuperOrganizations; + } + + public void setVisibleSuperOrganizations(String visibleSuperOrganizations) { + this.visibleSuperOrganizations = visibleSuperOrganizations; + } + + @Override + public String toString() { + return "PublisherAPI [isDefaultVersion=" + isDefaultVersion + ", description=" + description + ", wsdlUrl=" + + wsdlUrl + ", wadlUrl=" + wadlUrl + ", technicalOwner=" + technicalOwner + ", technicalOwnerEmail=" + + technicalOwnerEmail + ", businessOwner=" + businessOwner + ", businessOwnerEmail=" + + businessOwnerEmail + ", visibility=" + visibility + ", visibleRoles=" + visibleRoles + + ", visibleSuperOrganizations=" + visibleSuperOrganizations + ", visibleOrganizations=" + + visibleOrganizations + ", endpointSecured=" + endpointSecured + ", swaggerDefinition=" + + swaggerDefinition + ", asyncApiDefinition=" + asyncApiDefinition + ", endpointAuthDigest=" + + endpointAuthDigest + ", endpointUTUsername=" + endpointUTUsername + ", endpointUTPassword=" + + endpointUTPassword + ", transports=" + transports + ", inSequence=" + inSequence + ", outSequence=" + + outSequence + ", faultSequence=" + faultSequence + ", responseCache=" + responseCache + + ", cacheTimeout=" + cacheTimeout + ", endpointConfig=" + endpointConfig + + ", subscriptionAvailability=" + subscriptionAvailability + ", subscriptionAvailableOrgs=" + + subscriptionAvailableOrgs + ", implementation=" + implementation + ", productionMaxTps=" + + productionMaxTps + ", sandboxMaxTps=" + sandboxMaxTps + ", authorizationHeader=" + authorizationHeader + + ", apiKeyHeader=" + apiKeyHeader + ", apiSecurity=" + apiSecurity + ", enableSchemaValidation=" + + enableSchemaValidation + ", enableSubscriberVerification=" + enableSubscriberVerification + + ", enableStore=" + enableStore + ", testKey=" + testKey + ", contextTemplate=" + contextTemplate + + ", availableTierNames=" + availableTierNames + ", environments=" + environments + + ", corsConfiguration=" + corsConfiguration + ", websubSubscriptionConfiguration=" + + websubSubscriptionConfiguration + ", apiCategories=" + apiCategories + ", isMonetizationEnabled=" + + isMonetizationEnabled + ", monetizationProperties=" + monetizationProperties + ", keyManagers=" + + keyManagers + ", deploymentEnvironments=" + deploymentEnvironments + ", tags=" + tags + + ", accessControl=" + accessControl + ", accessControlRoles=" + accessControlRoles + + ", additionalProperties=" + additionalProperties + ", thumbnail=" + thumbnail + ", createdTime=" + + createdTime + ", lastUpdated=" + lastUpdated + ", soapToRestSequences=" + soapToRestSequences + + ", wsUriMapping=" + wsUriMapping + ", gatewayVendor=" + gatewayVendor + ", asyncTransportProtocols=" + + asyncTransportProtocols + ", versionTimestamp=" + versionTimestamp + ", audience=" + audience + + ", apiExternalProductionEndpoint=" + apiExternalProductionEndpoint + ", apiExternalSandboxEndpoint=" + + apiExternalSandboxEndpoint + ", redirectURL=" + redirectURL + ", apiOwner=" + apiOwner + ", vendor=" + + vendor + "]"; + } } /* diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapper.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapper.java index 1d0a2e63d4ee..a1c3dfe7f61a 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapper.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapper.java @@ -53,7 +53,7 @@ public interface APIMapper { @Mapping(source = "id", target = "uuid") @Mapping(source = "thumbnail", target = "thumbnailUrl") @Mapping(source = "availableTierNames", target = "availableTiers") - @Mapping(source = "visibleOrganizations", target = "visibleTenants") + @Mapping(source = "visibleSuperOrganizations", target = "visibleTenants") @Mapping(source = "subscriptionAvailableOrgs", target = "subscriptionAvailableTenants") @Mapping(source = "gatewayVendor", target = "gatewayVendor") API toApi(PublisherAPI api); @@ -64,7 +64,7 @@ public interface APIMapper { @Mapping(source = "thumbnailUrl", target = "thumbnail") @Mapping(source = "availableTiers", target = "availableTierNames") @Mapping(source = "uuid", target = "id") - @Mapping(source = "visibleTenants", target = "visibleOrganizations") + @Mapping(source = "visibleTenants", target = "visibleSuperOrganizations") @Mapping(source = "subscriptionAvailableTenants", target = "subscriptionAvailableOrgs") @Mapping(source = "gatewayVendor", target = "gatewayVendor") PublisherAPI toPublisherApi(API api); diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistryPersistenceUtil.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistryPersistenceUtil.java index 3cc2e386591a..3831fbf3b1b9 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistryPersistenceUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistryPersistenceUtil.java @@ -83,6 +83,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -186,7 +187,7 @@ public static GenericArtifact createAPIArtifactContent(GenericArtifact artifact, artifact.setAttribute(APIConstants.API_OVERVIEW_ENABLE_STORE, Boolean.toString(api.isEnableStore())); artifact.setAttribute(APIConstants.API_OVERVIEW_TESTKEY, api.getTestKey()); artifact.setAttribute(APIConstants.API_OVERVIEW_VERSION_COMPARABLE, api.getVersionTimestamp()); - + //Validate if the API has an unsupported context before setting it in the artifact String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); if (APIConstants.SUPER_TENANT_DOMAIN.equals(tenantDomain)) { @@ -864,6 +865,11 @@ private static API setResourceProperties(API api, Resource apiResource, String a } } api.setAccessControl(apiResource.getProperty(APIConstants.ACCESS_CONTROL)); + String visibleOrg = apiResource.getProperty(APIConstants.VISIBLE_ORGANIZATIONS); + if (visibleOrg != null) { + visibleOrg = visibleOrg.replace("+", " "); + } + api.setVisibleOrganizations(visibleOrg); String accessControlRoles = null; @@ -1901,4 +1907,84 @@ public static String extractProvider(String apiPath, String apiName) { private static RegistryService getRegistryService() { return ServiceReferenceHolder.getInstance().getRegistryService(); } + + public static Map getFields(String query) { + // Map to hold the final output + Map outputMap = new HashMap<>(); + + // Split the query by '&' + String[] parameters = query.split("&"); + + // Process each parameter + for (String parameter : parameters) { + // Split each parameter by '=' to get key and value + String[] keyValue = parameter.split("="); + + // Extract the key and value + String key = keyValue[0]; + String value = keyValue.length > 1 ? keyValue[1] : ""; + + // Map keys to the corresponding output format + switch (key) { + case "group": + outputMap.put("group", value); + break; + case "group.field": + outputMap.put("group.field", "overview_" + value); + break; + case "group.ngroups": + outputMap.put("group.ngroups", value); + break; + case "group.sort": + outputMap.put("group.sort", "overview_" + value); + break; + case "tags": + outputMap.put("tags", value); + break; + case "apiCategories_categoryName": + outputMap.put("apiCategories_categoryName", value.toLowerCase()); + break; + default: + // Add any other cases if needed + outputMap.put("overview_" + key, value.toLowerCase()); + break; + } + } + + outputMap.put("mediaType", "application/vnd.wso2-api+xml"); + + return outputMap; + } + + public static String buildFQStringForProperties(String query) { + String fq = ""; + boolean hasStoreViewRoles = query.contains("store_view_roles"); + boolean hasVisibleOrganizations = query.contains("visible_organizations"); + + // Build fq string based on the availability of store_view_roles and visible_organizations + if (hasStoreViewRoles) { + String storeViewRoles = extractValue(query, "store_view_roles"); + fq += "fq=store_view_roles_ss:" + storeViewRoles; + } + + if (hasVisibleOrganizations) { + if (!fq.isEmpty()) { + fq += "&"; + } + String visibleOrganizations = extractValue(query, "visible_organizations"); + fq += "fq=visible_organizations_ss:" + visibleOrganizations; + } + + return fq; + } + + private static String extractValue(String query, String paramName) { + String paramPrefix = paramName + "="; + int startIndex = query.indexOf(paramPrefix) + paramPrefix.length(); + int endIndex = query.indexOf("&", startIndex); + if (endIndex == -1) { + endIndex = query.length(); + } + return query.substring(startIndex, endIndex); + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java index 7b8f51bb7a09..4ebcc39f3b48 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java @@ -51,6 +51,7 @@ public class RegistrySearchUtil { public static final String SEARCH_AND_TAG = "&"; public static final String TAGS_SEARCH_TYPE_PREFIX = "tags"; public static final String NAME_TYPE_PREFIX = "name"; + public static final String AND_WITH_SPACES = " AND "; public static final String API_STATUS = "STATUS"; public static final String API_PROVIDER = "Provider"; public static final String DOCUMENT_INDEXER = "org.wso2.carbon.apimgt.impl.indexing.indexer.DocumentIndexer"; @@ -61,6 +62,9 @@ public class RegistrySearchUtil { public static final String SOAP_DEFINITION_INDEXER = "org.wso2.carbon.apimgt.impl.indexing.indexer" + ".SOAPAPIDefinitionIndexer"; public static final String STORE_VIEW_ROLES = "store_view_roles"; + public static final String STORE_VIEW_ROLES_FIELD = "store_view_roles_ss:"; + public static final String VISIBLE_ORGANIZATIONS = "visible_organizations"; + public static final String VISIBLE_ORGANIZATIONS_FIELD = "visible_organizations_ss:"; public static final String PUBLISHER_ROLES = "publisher_roles"; public static final String DOCUMENT_MEDIA_TYPE_KEY = "application/vnd.wso2-document\\+xml"; public static final String API_DEF_MEDIA_TYPE_KEY = "application/json"; @@ -241,12 +245,28 @@ private static Map getSearchAttributes(String searchQuery) { String apiState = ""; String publisherRoles = ""; Map attributes = new HashMap(); + String devportalFilterQuery = ""; + String devportalFilterQueryField = ""; for (String searchCriterea : searchQueries) { String[] keyVal = searchCriterea.split("="); if (STORE_VIEW_ROLES.equals(keyVal[0])) { - attributes.put("propertyName", keyVal[0]); - attributes.put("rightPropertyValue", keyVal[1]); - attributes.put("rightOp", "eq"); + if (!StringUtils.isEmpty(keyVal[1])) { + if (StringUtils.isEmpty(devportalFilterQuery)) { + devportalFilterQueryField = STORE_VIEW_ROLES; + devportalFilterQuery = keyVal[1]; + } else { + devportalFilterQuery += (AND_WITH_SPACES + STORE_VIEW_ROLES_FIELD + keyVal[1]); + } + } + } else if (VISIBLE_ORGANIZATIONS.equals(keyVal[0])) { + if (!StringUtils.isEmpty(keyVal[1])) { + if (StringUtils.isEmpty(devportalFilterQuery)) { + devportalFilterQueryField = VISIBLE_ORGANIZATIONS; + devportalFilterQuery = keyVal[1]; + } else { + devportalFilterQuery += (AND_WITH_SPACES + VISIBLE_ORGANIZATIONS_FIELD + keyVal[1]); + } + } } else if (PUBLISHER_ROLES.equals(keyVal[0])) { publisherRoles = keyVal[1]; } else { @@ -258,6 +278,11 @@ private static Map getSearchAttributes(String searchQuery) { attributes.put(keyVal[0], keyVal[1]); } } + if (!StringUtils.isEmpty(devportalFilterQueryField)) { + attributes.put("propertyName", devportalFilterQueryField); + attributes.put("rightPropertyValue", devportalFilterQuery); + attributes.put("rightOp", "eq"); + } //check whether the new document indexer is engaged RegistryConfigLoader registryConfig = RegistryConfigLoader.getInstance(); @@ -431,6 +456,28 @@ private static String getDevPortalRolesWrappedQuery(String query, UserContext co return criteria; } + private static String getOrganizationVisibilityWrappedQuery(String query, UserContext context) { + if (PersistenceUtil.isAdminUser(context)) { + log.debug("Admin user. no modifications to the query"); + return query; + } + + String orgName = context.getOrganization().getName(); + if (orgName != null && orgName.contains(" ")) { + orgName = orgName.replace(" ", "+"); + } + + String criteria = VISIBLE_ORGANIZATIONS + "=" + "(" + APIConstants.DEFAULT_VISIBLE_ORG + " OR " + orgName + ")"; + if (query != null && !query.trim().isEmpty()) { + criteria = criteria + "&" + query; + } + if (log.isDebugEnabled()) { + log.debug("Organization visibility wrapped query : " + criteria); + } + return criteria; + } + + private static String getUserRolesQuery(String[] userRoles, String skippedRoles) { StringBuilder rolesQuery = new StringBuilder(); @@ -523,10 +570,14 @@ public static String getDevPortalSearchQuery(String searchQuery, UserContext ctx } } - String apiOverviewStateCriteria = APIConstants.API_OVERVIEW_STATUS_SEARCH_TYPE_KEY; - apiOverviewStateCriteria = apiOverviewStateCriteria + getORBasedSearchCriteria(statusList); + if (!modifiedQuery.startsWith(APIConstants.API_OVERVIEW_STATUS_SEARCH_TYPE_KEY) && !modifiedQuery + .contains(APIConstants.SEARCH_AND_TAG + APIConstants.API_OVERVIEW_STATUS_SEARCH_TYPE_KEY)) { + + String apiOverviewStateCriteria = APIConstants.API_OVERVIEW_STATUS_SEARCH_TYPE_KEY; + apiOverviewStateCriteria = apiOverviewStateCriteria + getORBasedSearchCriteria(statusList); - modifiedQuery = modifiedQuery + APIConstants.SEARCH_AND_TAG + apiOverviewStateCriteria; + modifiedQuery = modifiedQuery + APIConstants.SEARCH_AND_TAG + apiOverviewStateCriteria; + } } modifiedQuery = RegistrySearchUtil.getDevPortalRolesWrappedQuery(extractQuery(modifiedQuery, true), ctx); return modifiedQuery; @@ -597,6 +648,7 @@ public static Map getDevPortalSearchAttributes(String searchQuer modifiedQuery = StringUtils.replaceIgnoreCase(modifiedQuery, searchString, APIConstants.LCSTATE_SEARCH_TYPE_KEY); } + modifiedQuery = RegistrySearchUtil.getOrganizationVisibilityWrappedQuery(modifiedQuery, ctx); modifiedQuery = RegistrySearchUtil.getDevPortalRolesWrappedQuery(modifiedQuery, ctx); modifiedQuery = RegistrySearchUtil.getDevPortalVisibilityWrappedQuery(modifiedQuery, isCrossTenant); Map attributes = RegistrySearchUtil.getSearchAttributes(modifiedQuery); diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImplTestCase.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImplTestCase.java index a496e38d05ca..ce46bd6f82ed 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImplTestCase.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImplTestCase.java @@ -16,8 +16,10 @@ package org.wso2.carbon.apimgt.persistence; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.times; +import static org.wso2.carbon.CarbonConstants.REGISTRY_SYSTEM_USERNAME; import java.sql.Timestamp; import java.time.LocalDateTime; @@ -66,6 +68,8 @@ import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.registry.core.session.UserRegistry; +import org.wso2.carbon.registry.indexing.indexer.IndexerException; +import org.wso2.carbon.registry.indexing.solr.SolrClient; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.core.UserRealm; import org.wso2.carbon.user.core.service.RealmService; @@ -75,7 +79,7 @@ @RunWith(PowerMockRunner.class) @PrepareForTest({ CarbonContext.class, RegistryPersistenceUtil.class, ServiceReferenceHolder.class, - PrivilegedCarbonContext.class, GovernanceUtils.class }) + PrivilegedCarbonContext.class, GovernanceUtils.class, SolrClient.class, RegistryPersistenceImpl.class }) public class RegistryPersistenceImplTestCase { private final int SUPER_TENANT_ID = -1234; private final String SUPER_TENANT_DOMAIN = "carbon.super"; @@ -83,7 +87,7 @@ public class RegistryPersistenceImplTestCase { private final String TENANT_DOMAIN = "wso2.com"; @Before - public void setupClass() throws UserStoreException { + public void setupClass() throws UserStoreException, IndexerException, APIManagementException { System.setProperty("carbon.home", ""); ServiceReferenceHolder serviceRefHolder = Mockito.mock(ServiceReferenceHolder.class); PowerMockito.mockStatic(ServiceReferenceHolder.class); @@ -99,7 +103,19 @@ public void setupClass() throws UserStoreException { CarbonContext context = Mockito.mock(CarbonContext.class); PowerMockito.when(CarbonContext.getThreadLocalCarbonContext()).thenReturn(context); + SolrClient solrClient = Mockito.mock(SolrClient.class); + PowerMockito.mockStatic(SolrClient.class); + PowerMockito.when(SolrClient.getInstance()).thenReturn(solrClient); + PowerMockito.mockStatic(GovernanceUtils.class); + GovernanceArtifact artifact = Mockito.mock(GovernanceArtifact.class); + List artifacts = new ArrayList(); + artifacts.add(artifact); + + PowerMockito.mockStatic(RegistryPersistenceImpl.class); + PowerMockito.when(RegistryPersistenceImpl.searchDevportalAPIs(anyString(), anyInt(), + any(), anyInt(), anyInt())) + .thenReturn(artifacts); } @Test @@ -117,14 +133,6 @@ public void testRegistrySelectionForSuperTenantUser() throws Exception { PrivilegedCarbonContext privilegedContext = Mockito.mock(PrivilegedCarbonContext.class); PowerMockito.when(PrivilegedCarbonContext.getThreadLocalCarbonContext()).thenReturn(privilegedContext); - PowerMockito.mockStatic(GovernanceUtils.class); - GovernanceArtifact artifact = Mockito.mock(GovernanceArtifact.class); - List artifacts = new ArrayList(); - artifacts.add(artifact); - PowerMockito.when(GovernanceUtils.findGovernanceArtifacts(Mockito.any(String.class), - Mockito.any(Registry.class), Mockito.any(String.class), Mockito.any(Boolean.class))) - .thenReturn(artifacts); - PowerMockito.mockStatic(RegistryPersistenceUtil.class); ServiceReferenceHolder serviceRefHolder = Mockito.mock(ServiceReferenceHolder.class); @@ -132,6 +140,9 @@ public void testRegistrySelectionForSuperTenantUser() throws Exception { PowerMockito.when(ServiceReferenceHolder.getInstance()).thenReturn(serviceRefHolder); RealmService realmService = Mockito.mock(RealmService.class); PowerMockito.when(serviceRefHolder.getRealmService()).thenReturn(realmService); + PowerMockito.when(serviceRefHolder.getRegistryService()).thenReturn(registryService); + UserRegistry userRegistry = Mockito.mock(UserRegistry.class); + PowerMockito.when(registryService.getRegistry(REGISTRY_SYSTEM_USERNAME, SUPER_TENANT_ID)).thenReturn(userRegistry); UserRealm realm = Mockito.mock(UserRealm.class); PowerMockito.when(realmService.getTenantUserRealm(SUPER_TENANT_ID)).thenReturn(realm); @@ -178,14 +189,6 @@ public void testRegistrySelectionForTenantUser() throws Exception { PrivilegedCarbonContext privilegedContext = Mockito.mock(PrivilegedCarbonContext.class); PowerMockito.when(PrivilegedCarbonContext.getThreadLocalCarbonContext()).thenReturn(privilegedContext); - PowerMockito.mockStatic(GovernanceUtils.class); - GovernanceArtifact artifact = Mockito.mock(GovernanceArtifact.class); - List artifacts = new ArrayList(); - artifacts.add(artifact); - PowerMockito.when(GovernanceUtils.findGovernanceArtifacts(Mockito.any(String.class), - Mockito.any(Registry.class), Mockito.any(String.class), Mockito.any(Boolean.class))) - .thenReturn(artifacts); - PowerMockito.mockStatic(RegistryPersistenceUtil.class); ServiceReferenceHolder serviceRefHolder = Mockito.mock(ServiceReferenceHolder.class); @@ -193,6 +196,9 @@ public void testRegistrySelectionForTenantUser() throws Exception { PowerMockito.when(ServiceReferenceHolder.getInstance()).thenReturn(serviceRefHolder); RealmService realmService = Mockito.mock(RealmService.class); PowerMockito.when(serviceRefHolder.getRealmService()).thenReturn(realmService); + PowerMockito.when(serviceRefHolder.getRegistryService()).thenReturn(registryService); + UserRegistry userRegistry = Mockito.mock(UserRegistry.class); + PowerMockito.when(registryService.getRegistry(REGISTRY_SYSTEM_USERNAME, TENANT_ID)).thenReturn(userRegistry); UserRealm realm = Mockito.mock(UserRealm.class); PowerMockito.when(realmService.getTenantUserRealm(TENANT_ID)).thenReturn(realm); @@ -241,14 +247,6 @@ public void testRegistrySelectionForTenantUserCrossTenatAccess() throws Exceptio PrivilegedCarbonContext privilegedContext = Mockito.mock(PrivilegedCarbonContext.class); PowerMockito.when(PrivilegedCarbonContext.getThreadLocalCarbonContext()).thenReturn(privilegedContext); - PowerMockito.mockStatic(GovernanceUtils.class); - GovernanceArtifact artifact = Mockito.mock(GovernanceArtifact.class); - List artifacts = new ArrayList(); - artifacts.add(artifact); - PowerMockito.when(GovernanceUtils.findGovernanceArtifacts(Mockito.any(String.class), - Mockito.any(Registry.class), Mockito.any(String.class), Mockito.any(Boolean.class))) - .thenReturn(artifacts); - PowerMockito.mockStatic(RegistryPersistenceUtil.class); ServiceReferenceHolder serviceRefHolder = Mockito.mock(ServiceReferenceHolder.class); @@ -257,6 +255,10 @@ public void testRegistrySelectionForTenantUserCrossTenatAccess() throws Exceptio RealmService realmService = Mockito.mock(RealmService.class); PowerMockito.when(serviceRefHolder.getRealmService()).thenReturn(realmService); + PowerMockito.when(serviceRefHolder.getRegistryService()).thenReturn(registryService); + UserRegistry userRegistry = Mockito.mock(UserRegistry.class); + PowerMockito.when(registryService.getRegistry(REGISTRY_SYSTEM_USERNAME, SUPER_TENANT_ID)).thenReturn(userRegistry); + UserRealm realm = Mockito.mock(UserRealm.class); PowerMockito.when(realmService.getTenantUserRealm(TENANT_ID)).thenReturn(realm); PowerMockito.doNothing().when(RegistryPersistenceUtil.class, "loadloadTenantAPIRXT", Mockito.any(String.class), diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapperTestCase.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapperTestCase.java index 5bd205fb9429..4b5a7c10affc 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapperTestCase.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/test/java/org/wso2/carbon/apimgt/persistence/mapper/APIMapperTestCase.java @@ -105,7 +105,7 @@ public void testAPItoPublisherApiAndBack() throws GovernanceException, APIManage PublisherAPI pubAPI = APIMapper.INSTANCE.toPublisherApi(api); Assert.assertEquals("API name does not match", api.getId().getName(), pubAPI.getApiName()); Assert.assertEquals("API uuid does not match", api.getUuid(), pubAPI.getId()); - Assert.assertTrue("Mapped api does not have status", pubAPI.toString().contains(api.getStatus())); + Assert.assertEquals("Mapped api does not have status", pubAPI.getStatus(), api.getStatus()); API mappedAPI = APIMapper.INSTANCE.toApi(pubAPI); Assert.assertEquals("Mapped api name does not match", mappedAPI.getId().getName(), api.getId().getName()); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/KeyManagerDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/KeyManagerDTO.java index 5d38b2739773..cfd81adad440 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/KeyManagerDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/KeyManagerDTO.java @@ -94,6 +94,7 @@ public static TokenTypeEnum fromValue(String v) { } } private TokenTypeEnum tokenType = TokenTypeEnum.DIRECT; + private List allowedOrganizations = new ArrayList(); /** **/ @@ -702,6 +703,23 @@ public void setTokenType(TokenTypeEnum tokenType) { this.tokenType = tokenType; } + /** + **/ + public KeyManagerDTO allowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + return this; + } + + + @ApiModelProperty(value = "") + @JsonProperty("allowedOrganizations") + public List getAllowedOrganizations() { + return allowedOrganizations; + } + public void setAllowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + } + @Override public boolean equals(java.lang.Object o) { @@ -746,12 +764,13 @@ public boolean equals(java.lang.Object o) { Objects.equals(global, keyManager.global) && Objects.equals(additionalProperties, keyManager.additionalProperties) && Objects.equals(permissions, keyManager.permissions) && - Objects.equals(tokenType, keyManager.tokenType); + Objects.equals(tokenType, keyManager.tokenType) && + Objects.equals(allowedOrganizations, keyManager.allowedOrganizations); } @Override public int hashCode() { - return Objects.hash(id, name, displayName, type, description, wellKnownEndpoint, introspectionEndpoint, clientRegistrationEndpoint, tokenEndpoint, displayTokenEndpoint, revokeEndpoint, displayRevokeEndpoint, userInfoEndpoint, authorizeEndpoint, endpoints, certificates, issuer, alias, scopeManagementEndpoint, availableGrantTypes, enableTokenGeneration, enableTokenEncryption, enableTokenHashing, enableMapOAuthConsumerApps, enableOAuthAppCreation, enableSelfValidationJWT, claimMapping, consumerKeyClaim, scopesClaim, tokenValidation, enabled, global, additionalProperties, permissions, tokenType); + return Objects.hash(id, name, displayName, type, description, wellKnownEndpoint, introspectionEndpoint, clientRegistrationEndpoint, tokenEndpoint, displayTokenEndpoint, revokeEndpoint, displayRevokeEndpoint, userInfoEndpoint, authorizeEndpoint, endpoints, certificates, issuer, alias, scopeManagementEndpoint, availableGrantTypes, enableTokenGeneration, enableTokenEncryption, enableTokenHashing, enableMapOAuthConsumerApps, enableOAuthAppCreation, enableSelfValidationJWT, claimMapping, consumerKeyClaim, scopesClaim, tokenValidation, enabled, global, additionalProperties, permissions, tokenType, allowedOrganizations); } @Override @@ -794,6 +813,7 @@ public String toString() { sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append(" permissions: ").append(toIndentedString(permissions)).append("\n"); sb.append(" tokenType: ").append(toIndentedString(tokenType)).append("\n"); + sb.append(" allowedOrganizations: ").append(toIndentedString(allowedOrganizations)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SettingsDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SettingsDTO.java index 20e0b73e10c7..7789d8abe596 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SettingsDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SettingsDTO.java @@ -26,6 +26,7 @@ public class SettingsDTO { private List scopes = new ArrayList(); private List gatewayTypes = new ArrayList(); private Boolean isJWTEnabledForLoginTokens = false; + private Boolean orgAccessControlEnabled = null; private List keyManagerConfiguration = new ArrayList(); private Boolean analyticsEnabled = null; private Boolean transactionCounterEnable = null; @@ -81,6 +82,24 @@ public void setIsJWTEnabledForLoginTokens(Boolean isJWTEnabledForLoginTokens) { this.isJWTEnabledForLoginTokens = isJWTEnabledForLoginTokens; } + /** + * Is Organization-based access control configuration enabled + **/ + public SettingsDTO orgAccessControlEnabled(Boolean orgAccessControlEnabled) { + this.orgAccessControlEnabled = orgAccessControlEnabled; + return this; + } + + + @ApiModelProperty(example = "true", value = "Is Organization-based access control configuration enabled ") + @JsonProperty("orgAccessControlEnabled") + public Boolean isOrgAccessControlEnabled() { + return orgAccessControlEnabled; + } + public void setOrgAccessControlEnabled(Boolean orgAccessControlEnabled) { + this.orgAccessControlEnabled = orgAccessControlEnabled; + } + /** **/ public SettingsDTO keyManagerConfiguration(List keyManagerConfiguration) { @@ -148,6 +167,7 @@ public boolean equals(java.lang.Object o) { return Objects.equals(scopes, settings.scopes) && Objects.equals(gatewayTypes, settings.gatewayTypes) && Objects.equals(isJWTEnabledForLoginTokens, settings.isJWTEnabledForLoginTokens) && + Objects.equals(orgAccessControlEnabled, settings.orgAccessControlEnabled) && Objects.equals(keyManagerConfiguration, settings.keyManagerConfiguration) && Objects.equals(analyticsEnabled, settings.analyticsEnabled) && Objects.equals(transactionCounterEnable, settings.transactionCounterEnable); @@ -155,7 +175,7 @@ public boolean equals(java.lang.Object o) { @Override public int hashCode() { - return Objects.hash(scopes, gatewayTypes, isJWTEnabledForLoginTokens, keyManagerConfiguration, analyticsEnabled, transactionCounterEnable); + return Objects.hash(scopes, gatewayTypes, isJWTEnabledForLoginTokens, orgAccessControlEnabled, keyManagerConfiguration, analyticsEnabled, transactionCounterEnable); } @Override @@ -166,6 +186,7 @@ public String toString() { sb.append(" scopes: ").append(toIndentedString(scopes)).append("\n"); sb.append(" gatewayTypes: ").append(toIndentedString(gatewayTypes)).append("\n"); sb.append(" isJWTEnabledForLoginTokens: ").append(toIndentedString(isJWTEnabledForLoginTokens)).append("\n"); + sb.append(" orgAccessControlEnabled: ").append(toIndentedString(orgAccessControlEnabled)).append("\n"); sb.append(" keyManagerConfiguration: ").append(toIndentedString(keyManagerConfiguration)).append("\n"); sb.append(" analyticsEnabled: ").append(toIndentedString(analyticsEnabled)).append("\n"); sb.append(" transactionCounterEnable: ").append(toIndentedString(transactionCounterEnable)).append("\n"); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyAllOfDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyAllOfDTO.java index d53f65d7e0c0..61ca35a6af83 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyAllOfDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyAllOfDTO.java @@ -35,6 +35,7 @@ public class SubscriptionThrottlePolicyAllOfDTO { private Boolean stopOnQuotaReach = false; private String billingPlan = null; private SubscriptionThrottlePolicyPermissionDTO permissions = null; + private List allowedOrganizations = new ArrayList(); /** **/ @@ -200,6 +201,23 @@ public void setPermissions(SubscriptionThrottlePolicyPermissionDTO permissions) this.permissions = permissions; } + /** + **/ + public SubscriptionThrottlePolicyAllOfDTO allowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + return this; + } + + + @ApiModelProperty(value = "") + @JsonProperty("allowedOrganizations") + public List getAllowedOrganizations() { + return allowedOrganizations; + } + public void setAllowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + } + @Override public boolean equals(java.lang.Object o) { @@ -218,12 +236,13 @@ public boolean equals(java.lang.Object o) { Objects.equals(customAttributes, subscriptionThrottlePolicyAllOf.customAttributes) && Objects.equals(stopOnQuotaReach, subscriptionThrottlePolicyAllOf.stopOnQuotaReach) && Objects.equals(billingPlan, subscriptionThrottlePolicyAllOf.billingPlan) && - Objects.equals(permissions, subscriptionThrottlePolicyAllOf.permissions); + Objects.equals(permissions, subscriptionThrottlePolicyAllOf.permissions) && + Objects.equals(allowedOrganizations, subscriptionThrottlePolicyAllOf.allowedOrganizations); } @Override public int hashCode() { - return Objects.hash(defaultLimit, monetization, rateLimitCount, rateLimitTimeUnit, subscriberCount, customAttributes, stopOnQuotaReach, billingPlan, permissions); + return Objects.hash(defaultLimit, monetization, rateLimitCount, rateLimitTimeUnit, subscriberCount, customAttributes, stopOnQuotaReach, billingPlan, permissions, allowedOrganizations); } @Override @@ -240,6 +259,7 @@ public String toString() { sb.append(" stopOnQuotaReach: ").append(toIndentedString(stopOnQuotaReach)).append("\n"); sb.append(" billingPlan: ").append(toIndentedString(billingPlan)).append("\n"); sb.append(" permissions: ").append(toIndentedString(permissions)).append("\n"); + sb.append(" allowedOrganizations: ").append(toIndentedString(allowedOrganizations)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyDTO.java index 24a1552cf6c0..3bd7155a4abf 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/admin/v1/dto/SubscriptionThrottlePolicyDTO.java @@ -40,6 +40,7 @@ public class SubscriptionThrottlePolicyDTO extends ThrottlePolicyDTO { private Boolean stopOnQuotaReach = false; private String billingPlan = null; private SubscriptionThrottlePolicyPermissionDTO permissions = null; + private List allowedOrganizations = new ArrayList(); /** * Maximum Complexity of the GraphQL query @@ -241,6 +242,23 @@ public void setPermissions(SubscriptionThrottlePolicyPermissionDTO permissions) this.permissions = permissions; } + /** + **/ + public SubscriptionThrottlePolicyDTO allowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + return this; + } + + + @ApiModelProperty(value = "") + @JsonProperty("allowedOrganizations") + public List getAllowedOrganizations() { + return allowedOrganizations; + } + public void setAllowedOrganizations(List allowedOrganizations) { + this.allowedOrganizations = allowedOrganizations; + } + @Override public boolean equals(java.lang.Object o) { @@ -261,12 +279,13 @@ public boolean equals(java.lang.Object o) { Objects.equals(customAttributes, subscriptionThrottlePolicy.customAttributes) && Objects.equals(stopOnQuotaReach, subscriptionThrottlePolicy.stopOnQuotaReach) && Objects.equals(billingPlan, subscriptionThrottlePolicy.billingPlan) && - Objects.equals(permissions, subscriptionThrottlePolicy.permissions); + Objects.equals(permissions, subscriptionThrottlePolicy.permissions) && + Objects.equals(allowedOrganizations, subscriptionThrottlePolicy.allowedOrganizations); } @Override public int hashCode() { - return Objects.hash(graphQLMaxComplexity, graphQLMaxDepth, defaultLimit, monetization, rateLimitCount, rateLimitTimeUnit, subscriberCount, customAttributes, stopOnQuotaReach, billingPlan, permissions); + return Objects.hash(graphQLMaxComplexity, graphQLMaxDepth, defaultLimit, monetization, rateLimitCount, rateLimitTimeUnit, subscriberCount, customAttributes, stopOnQuotaReach, billingPlan, permissions, allowedOrganizations); } @Override @@ -285,6 +304,7 @@ public String toString() { sb.append(" stopOnQuotaReach: ").append(toIndentedString(stopOnQuotaReach)).append("\n"); sb.append(" billingPlan: ").append(toIndentedString(billingPlan)).append("\n"); sb.append(" permissions: ").append(toIndentedString(permissions)).append("\n"); + sb.append(" allowedOrganizations: ").append(toIndentedString(allowedOrganizations)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/KeyManagerMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/KeyManagerMappingUtil.java index ad71274ab97b..faa70959c775 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/KeyManagerMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/KeyManagerMappingUtil.java @@ -218,6 +218,10 @@ public static KeyManagerDTO toKeyManagerDTO(KeyManagerConfigurationDTO keyManage jsonObject.remove(APIConstants.KeyManager.CONSUMER_KEY_CLAIM); } keyManagerDTO.setAdditionalProperties(new Gson().fromJson(jsonObject, Map.class)); + + if (keyManagerConfigurationDTO.getAllowedOrganizations() != null) { + keyManagerDTO.setAllowedOrganizations(keyManagerConfigurationDTO.getAllowedOrganizations()); + } return keyManagerDTO; } @@ -316,6 +320,10 @@ public static KeyManagerConfigurationDTO toKeyManagerConfigurationDTO(String ten } } keyManagerConfigurationDTO.setEndpoints(endpoints); + + if (keyManagerDTO.getAllowedOrganizations() != null) { + keyManagerConfigurationDTO.setAllowedOrganizations(keyManagerDTO.getAllowedOrganizations()); + } additionalProperties .put(APIConstants.KeyManager.ENABLE_OAUTH_APP_CREATION, keyManagerDTO.isEnableOAuthAppCreation()); additionalProperties.put(APIConstants.KeyManager.ENABLE_MAP_OAUTH_CONSUMER_APPS, diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/SettingsMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/SettingsMappingUtil.java index 99759d09ff2e..6138ef5355b3 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/SettingsMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/SettingsMappingUtil.java @@ -62,6 +62,7 @@ public SettingsDTO fromSettingsToDTO(Boolean isUserAvailable) throws APIManageme settingsDTO.setScopes(getScopeList()); settingsDTO.setGatewayTypes(APIUtil.getGatewayTypes()); settingsDTO.setIsJWTEnabledForLoginTokens(APIUtil.isJWTEnabledForPortals()); + settingsDTO.setOrgAccessControlEnabled(APIUtil.isOrganizationAccessControlEnabled()); return settingsDTO; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/throttling/SubscriptionThrottlePolicyMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/throttling/SubscriptionThrottlePolicyMappingUtil.java index f7ef5fc03953..afbbe47227f4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/throttling/SubscriptionThrottlePolicyMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/admin/v1/utils/mappings/throttling/SubscriptionThrottlePolicyMappingUtil.java @@ -89,6 +89,7 @@ public static SubscriptionThrottlePolicyDTO fromSubscriptionThrottlePolicyToDTO( policyDTO.setGraphQLMaxComplexity(subscriptionPolicy.getGraphQLMaxComplexity()); policyDTO.setGraphQLMaxDepth(subscriptionPolicy.getGraphQLMaxDepth()); policyDTO.setSubscriberCount(subscriptionPolicy.getSubscriberCount()); + policyDTO.setAllowedOrganizations(subscriptionPolicy.getAllowedOrganizations()); byte[] customAttributes = subscriptionPolicy.getCustomAttributes(); if (customAttributes != null) { @@ -140,6 +141,7 @@ public static SubscriptionPolicy fromSubscriptionThrottlePolicyDTOToModel(Subscr subscriptionPolicy = CommonThrottleMappingUtil.updateFieldsFromDTOToPolicy(dto, subscriptionPolicy); subscriptionPolicy.setBillingPlan(dto.getBillingPlan()); subscriptionPolicy.setStopOnQuotaReach(dto.isStopOnQuotaReach()); + subscriptionPolicy.setAllowedOrganizations(dto.getAllowedOrganizations()); if (!PolicyConstants.AI_API_QUOTA_TYPE_ENUM_VALUE.equals(quotaType)) { subscriptionPolicy.setRateLimitTimeUnit(dto.getRateLimitTimeUnit()); if (dto.getRateLimitCount() != null) { diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/resources/admin-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/resources/admin-api.yaml index 4905e5824783..dde1815da900 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/resources/admin-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/src/main/resources/admin-api.yaml @@ -4061,6 +4061,10 @@ components: example: FREE permissions: $ref: '#/components/schemas/SubscriptionThrottlePolicyPermission' + allowedOrganizations: + type: array + items: + type: string SubscriptionThrottlePolicyPermission: title: SubscriptionThrottlePolicyPermission required: @@ -5021,6 +5025,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + orgAccessControlEnabled: + type: boolean + description: | + Is Organization-based access control configuration enabled + example: true keyManagerConfiguration: type: array items: @@ -5282,7 +5291,10 @@ components: - EXCHANGED - DIRECT - BOTH - + allowedOrganizations: + type: array + items: + type: string KeyManagerEndpoint: title: Key Manager Endpoint. required: diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/java/org/wso2/carbon/apimgt/rest/api/common/RestApiConstants.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/java/org/wso2/carbon/apimgt/rest/api/common/RestApiConstants.java index c3f6773edd4e..7b439cc69280 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/java/org/wso2/carbon/apimgt/rest/api/common/RestApiConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/java/org/wso2/carbon/apimgt/rest/api/common/RestApiConstants.java @@ -39,6 +39,7 @@ public final class RestApiConstants { public static final String AUTHENTICATION_REQUIRED = "authentication_required"; public static final String HEADER_X_WSO2_TENANT = "x-wso2-tenant"; public static final String ORGANIZATION = "organization"; + public static final String ORGANIZATION_INFO = "organization_info"; public static final String SUB_ORGANIZATION = "sub_organization"; public static final String MASKED_TOKEN = "maskedToken"; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/admin-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/admin-api.yaml index 4905e5824783..dde1815da900 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/admin-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/admin-api.yaml @@ -4061,6 +4061,10 @@ components: example: FREE permissions: $ref: '#/components/schemas/SubscriptionThrottlePolicyPermission' + allowedOrganizations: + type: array + items: + type: string SubscriptionThrottlePolicyPermission: title: SubscriptionThrottlePolicyPermission required: @@ -5021,6 +5025,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + orgAccessControlEnabled: + type: boolean + description: | + Is Organization-based access control configuration enabled + example: true keyManagerConfiguration: type: array items: @@ -5282,7 +5291,10 @@ components: - EXCHANGED - DIRECT - BOTH - + allowedOrganizations: + type: array + items: + type: string KeyManagerEndpoint: title: Key Manager Endpoint. required: diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml index 993819c1a019..5e9e58d94d98 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml @@ -4399,6 +4399,11 @@ components: type: string readOnly: true example: 1651555310208 + visibility: + type: string + enum: + - PRIVATE + - SHARED_WITH_ORG ApplicationInfo: title: Application info object with basic application details type: object @@ -5587,6 +5592,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + orgAccessControlEnabled: + type: boolean + description: | + Is Organization-based access control configuration enabled + example: true userStorePasswordPattern: type: string description: The 'PasswordJavaRegEx' cofigured in the UserStoreManager diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml index 919a6d051230..716e1c09e6cb 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml @@ -10160,6 +10160,12 @@ components: example: [] items: type: string + visibleOrganizations: + type: array + description: The organizations that are able to access the API in Developer Portal + example: [] + items: + type: string mediationPolicies: type: array example: @@ -13198,6 +13204,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + orgAccessControlEnabled: + type: boolean + description: | + Is Organization-based access control configuration enabled + example: true allowSubscriptionValidationDisabling: type: boolean description: | diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDTO.java index 4853ace8b794..9255b21c4f96 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDTO.java @@ -188,6 +188,7 @@ public static VisibilityEnum fromValue(String v) { @Scope(name = "apim:api_manage", description="", value ="") private List visibleRoles = new ArrayList(); private List visibleTenants = new ArrayList(); + private List visibleOrganizations = new ArrayList(); private List mediationPolicies = new ArrayList(); private APIOperationPoliciesDTO apiPolicies = null; @@ -887,6 +888,24 @@ public void setVisibleTenants(List visibleTenants) { this.visibleTenants = visibleTenants; } + /** + * The organizations that are able to access the API in Developer Portal + **/ + public APIDTO visibleOrganizations(List visibleOrganizations) { + this.visibleOrganizations = visibleOrganizations; + return this; + } + + + @ApiModelProperty(example = "[]", value = "The organizations that are able to access the API in Developer Portal") + @JsonProperty("visibleOrganizations") + public List getVisibleOrganizations() { + return visibleOrganizations; + } + public void setVisibleOrganizations(List visibleOrganizations) { + this.visibleOrganizations = visibleOrganizations; + } + /** **/ public APIDTO mediationPolicies(List mediationPolicies) { @@ -1465,6 +1484,7 @@ public boolean equals(java.lang.Object o) { Objects.equals(visibility, API.visibility) && Objects.equals(visibleRoles, API.visibleRoles) && Objects.equals(visibleTenants, API.visibleTenants) && + Objects.equals(visibleOrganizations, API.visibleOrganizations) && Objects.equals(mediationPolicies, API.mediationPolicies) && Objects.equals(apiPolicies, API.apiPolicies) && Objects.equals(subscriptionAvailability, API.subscriptionAvailability) && @@ -1499,7 +1519,7 @@ public boolean equals(java.lang.Object o) { @Override public int hashCode() { - return Objects.hash(id, name, description, context, version, provider, lifeCycleStatus, wsdlInfo, wsdlUrl, responseCachingEnabled, cacheTimeout, hasThumbnail, isDefaultVersion, isRevision, revisionedApiId, revisionId, enableSchemaValidation, enableSubscriberVerification, type, audience, audiences, transport, tags, policies, apiThrottlingPolicy, authorizationHeader, apiKeyHeader, securityScheme, maxTps, visibility, visibleRoles, visibleTenants, mediationPolicies, apiPolicies, subscriptionAvailability, subscriptionAvailableTenants, additionalProperties, additionalPropertiesMap, monetization, accessControl, accessControlRoles, businessInformation, corsConfiguration, websubSubscriptionConfiguration, workflowStatus, createdTime, lastUpdatedTimestamp, lastUpdatedTime, endpointConfig, endpointImplementationType, subtypeConfiguration, scopes, operations, threatProtectionPolicies, categories, keyManagers, serviceInfo, advertiseInfo, gatewayVendor, gatewayType, asyncTransportProtocols, egress); + return Objects.hash(id, name, description, context, version, provider, lifeCycleStatus, wsdlInfo, wsdlUrl, responseCachingEnabled, cacheTimeout, hasThumbnail, isDefaultVersion, isRevision, revisionedApiId, revisionId, enableSchemaValidation, enableSubscriberVerification, type, audience, audiences, transport, tags, policies, apiThrottlingPolicy, authorizationHeader, apiKeyHeader, securityScheme, maxTps, visibility, visibleRoles, visibleTenants, visibleOrganizations, mediationPolicies, apiPolicies, subscriptionAvailability, subscriptionAvailableTenants, additionalProperties, additionalPropertiesMap, monetization, accessControl, accessControlRoles, businessInformation, corsConfiguration, websubSubscriptionConfiguration, workflowStatus, createdTime, lastUpdatedTimestamp, lastUpdatedTime, endpointConfig, endpointImplementationType, subtypeConfiguration, scopes, operations, threatProtectionPolicies, categories, keyManagers, serviceInfo, advertiseInfo, gatewayVendor, gatewayType, asyncTransportProtocols, egress); } @Override @@ -1539,6 +1559,7 @@ public String toString() { sb.append(" visibility: ").append(toIndentedString(visibility)).append("\n"); sb.append(" visibleRoles: ").append(toIndentedString(visibleRoles)).append("\n"); sb.append(" visibleTenants: ").append(toIndentedString(visibleTenants)).append("\n"); + sb.append(" visibleOrganizations: ").append(toIndentedString(visibleOrganizations)).append("\n"); sb.append(" mediationPolicies: ").append(toIndentedString(mediationPolicies)).append("\n"); sb.append(" apiPolicies: ").append(toIndentedString(apiPolicies)).append("\n"); sb.append(" subscriptionAvailability: ").append(toIndentedString(subscriptionAvailability)).append("\n"); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java index 8ff98b125d5d..c6b70378f436 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java @@ -42,6 +42,7 @@ public class SettingsDTO { private String defaultSubscriptionPolicy = null; private String authorizationHeader = null; private Boolean isJWTEnabledForLoginTokens = false; + private Boolean orgAccessControlEnabled = null; private Boolean allowSubscriptionValidationDisabling = true; private List customProperties = new ArrayList(); @@ -330,6 +331,24 @@ public void setIsJWTEnabledForLoginTokens(Boolean isJWTEnabledForLoginTokens) { this.isJWTEnabledForLoginTokens = isJWTEnabledForLoginTokens; } + /** + * Is Organization-based access control configuration enabled + **/ + public SettingsDTO orgAccessControlEnabled(Boolean orgAccessControlEnabled) { + this.orgAccessControlEnabled = orgAccessControlEnabled; + return this; + } + + + @ApiModelProperty(example = "true", value = "Is Organization-based access control configuration enabled ") + @JsonProperty("orgAccessControlEnabled") + public Boolean isOrgAccessControlEnabled() { + return orgAccessControlEnabled; + } + public void setOrgAccessControlEnabled(Boolean orgAccessControlEnabled) { + this.orgAccessControlEnabled = orgAccessControlEnabled; + } + /** * Allow subscription validation disabling for OAuth tokens **/ @@ -392,13 +411,14 @@ public boolean equals(java.lang.Object o) { Objects.equals(defaultSubscriptionPolicy, settings.defaultSubscriptionPolicy) && Objects.equals(authorizationHeader, settings.authorizationHeader) && Objects.equals(isJWTEnabledForLoginTokens, settings.isJWTEnabledForLoginTokens) && + Objects.equals(orgAccessControlEnabled, settings.orgAccessControlEnabled) && Objects.equals(allowSubscriptionValidationDisabling, settings.allowSubscriptionValidationDisabling) && Objects.equals(customProperties, settings.customProperties); } @Override public int hashCode() { - return Objects.hash(devportalUrl, environment, gatewayTypes, scopes, monetizationAttributes, subscriberContactAttributes, securityAuditProperties, externalStoresEnabled, docVisibilityEnabled, portalConfigurationOnlyModeEnabled, retryCallWithNewOAuthTokenEnabled, crossTenantSubscriptionEnabled, defaultAdvancePolicy, defaultSubscriptionPolicy, authorizationHeader, isJWTEnabledForLoginTokens, allowSubscriptionValidationDisabling, customProperties); + return Objects.hash(devportalUrl, environment, gatewayTypes, scopes, monetizationAttributes, subscriberContactAttributes, securityAuditProperties, externalStoresEnabled, docVisibilityEnabled, portalConfigurationOnlyModeEnabled, retryCallWithNewOAuthTokenEnabled, crossTenantSubscriptionEnabled, defaultAdvancePolicy, defaultSubscriptionPolicy, authorizationHeader, isJWTEnabledForLoginTokens, orgAccessControlEnabled, allowSubscriptionValidationDisabling, customProperties); } @Override @@ -422,6 +442,7 @@ public String toString() { sb.append(" defaultSubscriptionPolicy: ").append(toIndentedString(defaultSubscriptionPolicy)).append("\n"); sb.append(" authorizationHeader: ").append(toIndentedString(authorizationHeader)).append("\n"); sb.append(" isJWTEnabledForLoginTokens: ").append(toIndentedString(isJWTEnabledForLoginTokens)).append("\n"); + sb.append(" orgAccessControlEnabled: ").append(toIndentedString(orgAccessControlEnabled)).append("\n"); sb.append(" allowSubscriptionValidationDisabling: ").append(toIndentedString(allowSubscriptionValidationDisabling)).append("\n"); sb.append(" customProperties: ").append(toIndentedString(customProperties)).append("\n"); sb.append("}"); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIMappingUtil.java index 7138879d5a67..22d464fbe754 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIMappingUtil.java @@ -326,6 +326,13 @@ public static API fromDTOtoAPI(APIDTO dto, String provider) throws APIManagement model.setVisibleTenants(visibleTenants); } } + + if (dto.getVisibleOrganizations() != null && !dto.getVisibleOrganizations().isEmpty()) { + String visibleOrgs = StringUtils.join(dto.getVisibleOrganizations(), ','); + model.setVisibleOrganizations(visibleOrgs); + } else { + model.setVisibleOrganizations(APIConstants.DEFAULT_VISIBLE_ORG); + } List accessControlRoles = dto.getAccessControlRoles(); if (accessControlRoles == null || accessControlRoles.isEmpty()) { @@ -1388,6 +1395,13 @@ public static APIDTO fromAPItoDTO(API model, boolean preserveCredentials, if (model.getVisibleTenants() != null) { dto.setVisibleRoles(Arrays.asList(model.getVisibleTenants().split(","))); } + + if (model.getVisibleOrganizations() != null + || !APIConstants.DEFAULT_VISIBLE_ORG.equals(model.getVisibleOrganizations())) { + dto.setVisibleOrganizations(Arrays.asList(model.getVisibleOrganizations().split(","))); + } else { + dto.setVisibleOrganizations(Collections.EMPTY_LIST); + } if (model.getAdditionalProperties() != null) { JSONObject additionalProperties = model.getAdditionalProperties(); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java index 7a863624fbad..ab15f9147aef 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java @@ -1489,6 +1489,7 @@ public static API prepareToCreateAPIByDTO(APIDTO body, APIProvider apiProvider, throw new APIManagementException(errorMessage, ExceptionCodes.INVALID_USER_ROLES); } } + //Get all existing versions of api been adding List apiVersions = apiProvider.getApiVersionsMatchingApiNameAndOrganization(body.getName(), diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/SettingsMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/SettingsMappingUtil.java index 9eca18d3923c..7e18262cc610 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/SettingsMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/SettingsMappingUtil.java @@ -87,6 +87,7 @@ public SettingsDTO fromSettingstoDTO(Boolean isUserAvailable, String organizatio settingsDTO.setExternalStoresEnabled( APIUtil.isExternalStoresEnabled(RestApiCommonUtil.getLoggedInUserTenantDomain())); settingsDTO.setDocVisibilityEnabled(APIUtil.isDocVisibilityLevelsEnabled()); + settingsDTO.setOrgAccessControlEnabled(APIUtil.isOrganizationAccessControlEnabled()); settingsDTO.setPortalConfigurationOnlyModeEnabled(APIUtil.isPortalConfigurationOnlyModeEnabled()); settingsDTO.setCrossTenantSubscriptionEnabled(APIUtil.isCrossTenantSubscriptionsEnabled()); settingsDTO.setAllowSubscriptionValidationDisabling( diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml index 919a6d051230..716e1c09e6cb 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml @@ -10160,6 +10160,12 @@ components: example: [] items: type: string + visibleOrganizations: + type: array + description: The organizations that are able to access the API in Developer Portal + example: [] + items: + type: string mediationPolicies: type: array example: @@ -13198,6 +13204,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + orgAccessControlEnabled: + type: boolean + description: | + Is Organization-based access control configuration enabled + example: true allowSubscriptionValidationDisabling: type: boolean description: | diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApplicationDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApplicationDTO.java index 225f12efa074..ec38b804982a 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApplicationDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApplicationDTO.java @@ -73,6 +73,38 @@ public static TokenTypeEnum fromValue(String v) { private String createdTime = null; private String updatedTime = null; + @XmlType(name="VisibilityEnum") + @XmlEnum(String.class) + public enum VisibilityEnum { + PRIVATE("PRIVATE"), + SHARED_WITH_ORG("SHARED_WITH_ORG"); + private String value; + + VisibilityEnum (String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static VisibilityEnum fromValue(String v) { + for (VisibilityEnum b : VisibilityEnum.values()) { + if (String.valueOf(b.value).equals(v)) { + return b; + } + } +return null; + } + } + private VisibilityEnum visibility = null; + /** **/ public ApplicationDTO applicationId(String applicationId) { @@ -334,6 +366,23 @@ public void setUpdatedTime(String updatedTime) { this.updatedTime = updatedTime; } + /** + **/ + public ApplicationDTO visibility(VisibilityEnum visibility) { + this.visibility = visibility; + return this; + } + + + @ApiModelProperty(value = "") + @JsonProperty("visibility") + public VisibilityEnum getVisibility() { + return visibility; + } + public void setVisibility(VisibilityEnum visibility) { + this.visibility = visibility; + } + @Override public boolean equals(java.lang.Object o) { @@ -358,12 +407,13 @@ public boolean equals(java.lang.Object o) { Objects.equals(owner, application.owner) && Objects.equals(hashEnabled, application.hashEnabled) && Objects.equals(createdTime, application.createdTime) && - Objects.equals(updatedTime, application.updatedTime); + Objects.equals(updatedTime, application.updatedTime) && + Objects.equals(visibility, application.visibility); } @Override public int hashCode() { - return Objects.hash(applicationId, name, throttlingPolicy, description, tokenType, status, groups, subscriptionCount, keys, attributes, subscriptionScopes, owner, hashEnabled, createdTime, updatedTime); + return Objects.hash(applicationId, name, throttlingPolicy, description, tokenType, status, groups, subscriptionCount, keys, attributes, subscriptionScopes, owner, hashEnabled, createdTime, updatedTime, visibility); } @Override @@ -386,6 +436,7 @@ public String toString() { sb.append(" hashEnabled: ").append(toIndentedString(hashEnabled)).append("\n"); sb.append(" createdTime: ").append(toIndentedString(createdTime)).append("\n"); sb.append(" updatedTime: ").append(toIndentedString(updatedTime)).append("\n"); + sb.append(" visibility: ").append(toIndentedString(visibility)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java index 2c96c6462d5e..839382967d6f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java @@ -35,6 +35,7 @@ public class SettingsDTO { private Boolean isAnonymousModeEnabled = true; private Boolean isPasswordChangeEnabled = true; private Boolean isJWTEnabledForLoginTokens = false; + private Boolean orgAccessControlEnabled = null; private String userStorePasswordPattern = null; private String passwordPolicyPattern = null; private Integer passwordPolicyMinLength = null; @@ -248,6 +249,24 @@ public void setIsJWTEnabledForLoginTokens(Boolean isJWTEnabledForLoginTokens) { this.isJWTEnabledForLoginTokens = isJWTEnabledForLoginTokens; } + /** + * Is Organization-based access control configuration enabled + **/ + public SettingsDTO orgAccessControlEnabled(Boolean orgAccessControlEnabled) { + this.orgAccessControlEnabled = orgAccessControlEnabled; + return this; + } + + + @ApiModelProperty(example = "true", value = "Is Organization-based access control configuration enabled ") + @JsonProperty("orgAccessControlEnabled") + public Boolean isOrgAccessControlEnabled() { + return orgAccessControlEnabled; + } + public void setOrgAccessControlEnabled(Boolean orgAccessControlEnabled) { + this.orgAccessControlEnabled = orgAccessControlEnabled; + } + /** * The 'PasswordJavaRegEx' cofigured in the UserStoreManager **/ @@ -396,6 +415,7 @@ public boolean equals(java.lang.Object o) { Objects.equals(isAnonymousModeEnabled, settings.isAnonymousModeEnabled) && Objects.equals(isPasswordChangeEnabled, settings.isPasswordChangeEnabled) && Objects.equals(isJWTEnabledForLoginTokens, settings.isJWTEnabledForLoginTokens) && + Objects.equals(orgAccessControlEnabled, settings.orgAccessControlEnabled) && Objects.equals(userStorePasswordPattern, settings.userStorePasswordPattern) && Objects.equals(passwordPolicyPattern, settings.passwordPolicyPattern) && Objects.equals(passwordPolicyMinLength, settings.passwordPolicyMinLength) && @@ -407,7 +427,7 @@ public boolean equals(java.lang.Object o) { @Override public int hashCode() { - return Objects.hash(grantTypes, scopes, applicationSharingEnabled, mapExistingAuthApps, apiGatewayEndpoint, monetizationEnabled, recommendationEnabled, isUnlimitedTierPaid, identityProvider, isAnonymousModeEnabled, isPasswordChangeEnabled, isJWTEnabledForLoginTokens, userStorePasswordPattern, passwordPolicyPattern, passwordPolicyMinLength, passwordPolicyMaxLength, apiChatEnabled, aiAuthTokenProvided, marketplaceAssistantEnabled); + return Objects.hash(grantTypes, scopes, applicationSharingEnabled, mapExistingAuthApps, apiGatewayEndpoint, monetizationEnabled, recommendationEnabled, isUnlimitedTierPaid, identityProvider, isAnonymousModeEnabled, isPasswordChangeEnabled, isJWTEnabledForLoginTokens, orgAccessControlEnabled, userStorePasswordPattern, passwordPolicyPattern, passwordPolicyMinLength, passwordPolicyMaxLength, apiChatEnabled, aiAuthTokenProvided, marketplaceAssistantEnabled); } @Override @@ -427,6 +447,7 @@ public String toString() { sb.append(" isAnonymousModeEnabled: ").append(toIndentedString(isAnonymousModeEnabled)).append("\n"); sb.append(" isPasswordChangeEnabled: ").append(toIndentedString(isPasswordChangeEnabled)).append("\n"); sb.append(" isJWTEnabledForLoginTokens: ").append(toIndentedString(isJWTEnabledForLoginTokens)).append("\n"); + sb.append(" orgAccessControlEnabled: ").append(toIndentedString(orgAccessControlEnabled)).append("\n"); sb.append(" userStorePasswordPattern: ").append(toIndentedString(userStorePasswordPattern)).append("\n"); sb.append(" passwordPolicyPattern: ").append(toIndentedString(passwordPolicyPattern)).append("\n"); sb.append(" passwordPolicyMinLength: ").append(toIndentedString(passwordPolicyMinLength)).append("\n"); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java index c22b2114da0f..6206ec43427d 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java @@ -41,6 +41,7 @@ import org.wso2.carbon.apimgt.api.model.Documentation; import org.wso2.carbon.apimgt.api.model.DocumentationContent; import org.wso2.carbon.apimgt.api.model.Environment; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.api.model.ResourceFile; import org.wso2.carbon.apimgt.api.model.Tier; import org.wso2.carbon.apimgt.api.model.graphql.queryanalysis.GraphqlComplexityInfo; @@ -94,7 +95,10 @@ public Response apisGet(Integer limit, Integer offset, String xWSO2Tenant, Strin query = query == null ? "" : query; APIListDTO apiListDTO = new APIListDTO(); try { - String organization = RestApiUtil.getValidatedOrganization(messageContext); + String superOrganization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); + orgInfo.setSuperOrganization(superOrganization); + String username = RestApiCommonUtil.getLoggedInUsername(); APIConsumer apiConsumer = RestApiCommonUtil.getConsumer(username); @@ -104,14 +108,21 @@ public Response apisGet(Integer limit, Integer offset, String xWSO2Tenant, Strin .replace(APIConstants.CONTENT_SEARCH_TYPE_PREFIX + ":", APIConstants.NAME_TYPE_PREFIX + ":"); } - Map allMatchedApisMap = apiConsumer.searchPaginatedAPIs(query, organization, offset, - limit, null, null); - + //Map allMatchedApisMap = apiConsumer.searchPaginatedAPIs(query, superOrganization, offset, + // limit, null, null); + Map allMatchedApisMap; + if (APIUtil.isOrganizationAccessControlEnabled()) { + allMatchedApisMap = apiConsumer.searchPaginatedAPIs(query, orgInfo, offset, + limit, null, null); + } else { + allMatchedApisMap = apiConsumer.searchPaginatedAPIs(query, superOrganization, offset, + limit, null, null); + } Set sortedSet = (Set) allMatchedApisMap.get("apis"); // This is a SortedSet ArrayList allMatchedApis = new ArrayList<>(sortedSet); - apiListDTO = APIMappingUtil.fromAPIListToDTO(allMatchedApis, organization); + apiListDTO = APIMappingUtil.fromAPIListToDTO(allMatchedApis, superOrganization); //Add pagination section in the response Object totalLength = allMatchedApisMap.get("length"); Integer totalAvailableAPis = 0; @@ -141,8 +152,10 @@ public Response apisGet(Integer limit, Integer offset, String xWSO2Tenant, Strin @Override public Response apisApiIdGet(String apiId, String xWSO2Tenant, String ifNoneMatch, MessageContext messageContext) throws APIManagementException { - String organization = RestApiUtil.getValidatedOrganization(messageContext); - return Response.ok().entity(getAPIByAPIId(apiId, organization)).build(); + String superOrganization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo userOrgInfo = RestApiUtil.getOrganizationInfo(messageContext); + userOrgInfo.setSuperOrganization(superOrganization); + return Response.ok().entity(getAPIByAPIId(apiId, superOrganization, userOrgInfo)).build(); } @@ -795,8 +808,10 @@ public Response apisApiIdSdksLanguageGet(String apiId, String language, String x String message = "Error generating the SDK. API id or language should not be empty"; RestApiUtil.handleBadRequest(message, log); } - String organization = RestApiUtil.getValidatedOrganization(messageContext); - APIDTO api = getAPIByAPIId(apiId, organization); + String superOrganization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo userOrgInfo = RestApiUtil.getOrganizationInfo(messageContext); + userOrgInfo.setSuperOrganization(superOrganization); + APIDTO api = getAPIByAPIId(apiId, superOrganization, userOrgInfo); APIClientGenerationManager apiClientGenerationManager = new APIClientGenerationManager(); Map sdkArtifacts; String swaggerDefinition = api.getApiDefinition(); @@ -1136,10 +1151,12 @@ public Response getWSDLOfAPI(String apiId, String environmentName, String ifNone @Override public Response apisApiIdSubscriptionPoliciesGet(String apiId, String xWSO2Tenant, String ifNoneMatch, MessageContext messageContext) throws APIManagementException { - String organization = RestApiUtil.getValidatedOrganization(messageContext); - APIDTO apiInfo = getAPIByAPIId(apiId, organization); + String superOrganization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo userOrgInfo = RestApiUtil.getOrganizationInfo(messageContext); + userOrgInfo.setSuperOrganization(superOrganization); + APIDTO apiInfo = getAPIByAPIId(apiId, superOrganization, userOrgInfo); List availableThrottlingPolicyList = new ThrottlingPoliciesApiServiceImpl() - .getThrottlingPolicyList(ThrottlingPolicyDTO.PolicyLevelEnum.SUBSCRIPTION.toString(), organization); + .getThrottlingPolicyList(ThrottlingPolicyDTO.PolicyLevelEnum.SUBSCRIPTION.toString(), superOrganization); if (apiInfo != null ) { List apiTiers = apiInfo.getTiers(); @@ -1158,18 +1175,32 @@ public Response apisApiIdSubscriptionPoliciesGet(String apiId, String xWSO2Tenan return null; } - private APIDTO getAPIByAPIId(String apiId, String organization) { + private APIDTO getAPIByAPIId(String apiId, String organization, OrganizationInfo userOrgInfo) { try { APIConsumer apiConsumer = RestApiCommonUtil.getLoggedInUserConsumer(); ApiTypeWrapper api = apiConsumer.getAPIorAPIProductByUUID(apiId, organization); String status = api.getStatus(); + String userOrg = userOrgInfo.getOrganizationSelector(); - // Extracting clicked API name by the user, for the recommendation system String userName = RestApiCommonUtil.getLoggedInUsername(); + + if (!api.isAPIProduct() && !RestApiUtil.isOrganizationVisibilityAllowed(userName, + api.getApi().getVisibleOrganizations(), userOrg)) { + RestApiUtil.handleAuthorizationFailure(RestApiConstants.RESOURCE_API, apiId, log); + } + + // Extracting clicked API name by the user, for the recommendation system apiConsumer.publishClickedAPI(api, userName, organization); if (APIConstants.PUBLISHED.equals(status) || APIConstants.PROTOTYPED.equals(status) || APIConstants.DEPRECATED.equals(status)) { + if (!api.isAPIProduct()) { + // Add only organization specific tiers + Set tiers = APIUtil.getAllowedTiersForTheOrganization(api.getApi().getAvailableTiers(), + userOrgInfo.getOrganizationSelector(), userOrgInfo.getSuperOrganization()); + api.getApi().removeAllTiers(); + api.getApi().setAvailableTiers(tiers); + } APIDTO apidto = APIMappingUtil.fromAPItoDTO(api, organization); long subscriptionCountOfAPI = apiConsumer.getSubscriptionCountOfAPI(apiId, organization); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApplicationsApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApplicationsApiServiceImpl.java index 61b711d67bf3..252dc17de04e 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApplicationsApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApplicationsApiServiceImpl.java @@ -44,6 +44,7 @@ import org.wso2.carbon.apimgt.api.model.Application; import org.wso2.carbon.apimgt.api.model.ApplicationConstants; import org.wso2.carbon.apimgt.api.model.OAuthApplicationInfo; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.api.model.Scope; import org.wso2.carbon.apimgt.api.model.Subscriber; import org.wso2.carbon.apimgt.impl.APIConstants; @@ -62,6 +63,7 @@ import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIKeyGenerateRequestDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIKeyRevokeRequestDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationDTO.VisibilityEnum; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationInfoDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationKeyDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationKeyGenerateRequestDTO; @@ -137,12 +139,14 @@ public Response applicationsGet(String groupId, String query, String sortBy, Str groupId = RestApiUtil.getLoggedInUserGroupId(); try { String organization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); APIConsumer apiConsumer = RestApiCommonUtil.getConsumer(username); Subscriber subscriber = new Subscriber(username); Application[] applications; + String sharedOrganization = orgInfo.getOrganizationSelector(); applications = apiConsumer .getApplicationsWithPagination(new Subscriber(username), groupId, offset, limit, query, sortBy, - sortOrder, organization); + sortOrder, organization, sharedOrganization); if (applications != null) { JSONArray applicationAttributesFromConfig = apiConsumer.getAppAttributesFromConfig(username); for (Application application : applications) { @@ -243,15 +247,16 @@ public Response applicationsGet(String groupId, String query, String sortBy, Str } String organization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); if (APIUtil.isApplicationExist(ownerId, applicationDTO.getName(), applicationGroupId, organization) && update != null && update) { int appId = APIUtil.getApplicationId(applicationDTO.getName(), ownerId); Application oldApplication = apiConsumer.getApplicationById(appId); application = preProcessAndUpdateApplication(ownerId, applicationDTO, oldApplication, - oldApplication.getUUID()); + oldApplication.getUUID(), orgInfo.getOrganizationSelector()); } else { - application = preProcessAndAddApplication(ownerId, applicationDTO, organization); + application = preProcessAndAddApplication(ownerId, applicationDTO, organization, orgInfo.getOrganizationSelector()); update = Boolean.FALSE; } @@ -323,7 +328,9 @@ public Response applicationsPost(ApplicationDTO body, MessageContext messageCont body.setTokenType(ApplicationDTO.TokenTypeEnum.JWT); String organization = RestApiUtil.getValidatedOrganization(messageContext); - Application createdApplication = preProcessAndAddApplication(username, body, organization); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); + Application createdApplication = preProcessAndAddApplication(username, body, organization, + orgInfo.getOrganizationSelector()); ApplicationDTO createdApplicationDTO = ApplicationMappingUtil.fromApplicationtoDTO(createdApplication); //to be set as the Location header @@ -356,8 +363,8 @@ public Response applicationsPost(ApplicationDTO body, MessageContext messageCont * @param organization Identifier of an organization * @return Created application */ - private Application preProcessAndAddApplication(String username, ApplicationDTO applicationDto, String organization) - throws APIManagementException { + private Application preProcessAndAddApplication(String username, ApplicationDTO applicationDto, String organization, + String sharedOrganization) throws APIManagementException { APIConsumer apiConsumer = APIManagerFactory.getInstance().getAPIConsumer(username); //validate the tier specified for the application @@ -375,6 +382,12 @@ private Application preProcessAndAddApplication(String username, ApplicationDTO //subscriber field of the body is not honored. It is taken from the context Application application = ApplicationMappingUtil.fromDTOtoApplication(applicationDto, username); + + application.setSharedOrganization(APIConstants.DEFAULT_APP_SHARING_KEYWORD); // default + if ((applicationDto.getVisibility() != null) + && applicationDto.getVisibility() == VisibilityEnum.SHARED_WITH_ORG && sharedOrganization != null) { + application.setSharedOrganization(sharedOrganization); + } int applicationId = apiConsumer.addApplication(application, username, organization); @@ -395,6 +408,7 @@ public Response applicationsApplicationIdGet(String applicationId, String ifNone String username = RestApiCommonUtil.getLoggedInUsername(); try { String organization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); APIConsumer apiConsumer = APIManagerFactory.getInstance().getAPIConsumer(username); Application application = apiConsumer.getApplicationByUUID(applicationId, organization); if (application != null) { @@ -419,7 +433,9 @@ public Response applicationsApplicationIdGet(String applicationId, String ifNone } } application.setApplicationAttributes(applicationAttributes); - if (RestAPIStoreUtils.isUserAccessAllowedForApplication(application)) { + if (RestAPIStoreUtils.isUserAccessAllowedForApplication(application) + || (orgInfo.getOrganizationSelector() != null + && orgInfo.getOrganizationSelector().equals(application.getSharedOrganization()))) { ApplicationDTO applicationDTO = ApplicationMappingUtil.fromApplicationtoDTO(application); applicationDTO.setHashEnabled(OAuthServerConfiguration.getInstance().isClientSecretHashEnabled()); Set scopes = apiConsumer @@ -468,8 +484,9 @@ public Response applicationsApplicationIdPut(String applicationId, ApplicationDT "A duplicate application already exists by the name - " + body.getName()); } } + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); Application updatedApplication = preProcessAndUpdateApplication(username, body, oldApplication, - applicationId); + applicationId, orgInfo.getOrganizationSelector()); ApplicationDTO updatedApplicationDTO = ApplicationMappingUtil.fromApplicationtoDTO(updatedApplication); return Response.ok().entity(updatedApplicationDTO).build(); @@ -532,7 +549,7 @@ public Response applicationsApplicationIdResetThrottlePolicyPost(String applicat * @return Updated application */ private Application preProcessAndUpdateApplication(String username, ApplicationDTO applicationDto, - Application oldApplication, String applicationId) throws APIManagementException { + Application oldApplication, String applicationId, String sharedOrganization) throws APIManagementException { APIConsumer apiConsumer = APIManagerFactory.getInstance().getAPIConsumer(username); Object applicationAttributesFromUser = applicationDto.getAttributes(); Map applicationAttributes = new ObjectMapper() @@ -548,6 +565,15 @@ private Application preProcessAndUpdateApplication(String username, ApplicationD //we do not honor the application id which is sent via the request body application.setUUID(oldApplication != null ? oldApplication.getUUID() : null); + application.setSharedOrganization(oldApplication.getSharedOrganization()); // default + if (applicationDto.getVisibility() != null) { + if (applicationDto.getVisibility() == VisibilityEnum.SHARED_WITH_ORG && sharedOrganization != null) { + application.setSharedOrganization(sharedOrganization); + } else if (applicationDto.getVisibility() == VisibilityEnum.PRIVATE) { + application.setSharedOrganization(APIConstants.DEFAULT_APP_SHARING_KEYWORD); + } + + } apiConsumer.updateApplication(application); //retrieves the updated application and send as the response @@ -897,16 +923,19 @@ public Response applicationsApplicationIdKeysKeyTypeCleanUpPost(String applicati * Used to get all keys of an application * * @param applicationUUID Id of the application + * @param orgInfo * @return List of application keys */ - private Set getApplicationKeys(String applicationUUID, String tenantDomain) { + private Set getApplicationKeys(String applicationUUID, String tenantDomain, OrganizationInfo orgInfo) { String username = RestApiCommonUtil.getLoggedInUsername(); try { APIConsumer apiConsumer = APIManagerFactory.getInstance().getAPIConsumer(username); Application application = apiConsumer.getLightweightApplicationByUUID(applicationUUID); if (application != null) { - if (RestAPIStoreUtils.isUserAccessAllowedForApplication(application)) { + if (RestAPIStoreUtils.isUserAccessAllowedForApplication(application) + || (orgInfo != null && orgInfo.getOrganizationSelector() != null + && orgInfo.getOrganizationSelector().equals(application.getSharedOrganization()))) { return apiConsumer.getApplicationKeysOfApplication(application.getId(), tenantDomain); } else { RestApiUtil.handleAuthorizationFailure(RestApiConstants.RESOURCE_APPLICATION, applicationUUID, log); @@ -928,7 +957,7 @@ private Set getApplicationKeys(String applicationUUID, String tenantDoma */ private Set getApplicationKeys(String applicationUUID) { - return getApplicationKeys(applicationUUID, null); + return getApplicationKeys(applicationUUID, null, null); } @Override @@ -1204,7 +1233,8 @@ public Response applicationsApplicationIdOauthKeysGet(String applicationId, String xWso2Tenant, MessageContext messageContext) throws APIManagementException { String organization = RestApiUtil.getValidatedOrganization(messageContext); - Set applicationKeys = getApplicationKeys(applicationId, organization); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); + Set applicationKeys = getApplicationKeys(applicationId, organization, orgInfo); List keyDTOList = new ArrayList<>(); ApplicationKeyListDTO applicationKeyListDTO = new ApplicationKeyListDTO(); applicationKeyListDTO.setCount(0); @@ -1270,9 +1300,11 @@ public Response applicationsApplicationIdOauthKeysKeyMappingIdGenerateTokenPost( String username = RestApiCommonUtil.getLoggedInUsername(); APIConsumer apiConsumer = RestApiCommonUtil.getConsumer(username); Application application = apiConsumer.getApplicationByUUID(applicationId); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); if (application != null) { - if (RestAPIStoreUtils.isUserAccessAllowedForApplication(application)) { + if (RestAPIStoreUtils.isUserAccessAllowedForApplication(application) || (orgInfo.getOrganizationSelector() != null + && orgInfo.getOrganizationSelector().equals(application.getSharedOrganization()))) { ApplicationKeyDTO appKey = getApplicationKeyByAppIDAndKeyMapping(applicationId, keyMappingId); if (appKey != null) { String jsonInput = null; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/KeyManagersApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/KeyManagersApiServiceImpl.java index cab23de7858e..a0af9db2f833 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/KeyManagersApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/KeyManagersApiServiceImpl.java @@ -7,11 +7,13 @@ import org.wso2.carbon.apimgt.api.APIConsumer; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.dto.KeyManagerConfigurationDTO; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.impl.APIAdminImpl; import org.wso2.carbon.apimgt.impl.APIConsumerImpl; import org.wso2.carbon.apimgt.rest.api.common.RestApiCommonUtil; import org.wso2.carbon.apimgt.rest.api.store.v1.KeyManagersApiService; import org.wso2.carbon.apimgt.rest.api.store.v1.mappings.KeyManagerMappingUtil; +import org.wso2.carbon.apimgt.rest.api.store.v1.utils.APIUtils; import org.wso2.carbon.apimgt.rest.api.util.utils.RestApiUtil; import java.util.List; @@ -26,6 +28,7 @@ public Response keyManagersGet(String xWSO2Tenant, MessageContext messageContext String organization = RestApiUtil.getOrganization(messageContext); try { + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); APIAdmin apiAdmin = new APIAdminImpl(); APIConsumer apiConsumer = new APIConsumerImpl(); String username = RestApiCommonUtil.getLoggedInUsername(); @@ -34,6 +37,8 @@ public Response keyManagersGet(String xWSO2Tenant, MessageContext messageContext List globalKeyManagerConfigurations = apiAdmin.getGlobalKeyManagerConfigurations(); permittedKeyManagerConfigurations.addAll(globalKeyManagerConfigurations); + permittedKeyManagerConfigurations = APIUtils + .filterAllowedKeyManagersForOrganizations(permittedKeyManagerConfigurations, orgInfo); return Response.ok(KeyManagerMappingUtil.toKeyManagerListDto(permittedKeyManagerConfigurations)).build(); } catch (APIManagementException e) { diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java index 8707ee31f411..1af887badaf6 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java @@ -27,7 +27,9 @@ import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.api.model.Documentation; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiCommonUtil; import org.wso2.carbon.apimgt.rest.api.store.v1.SearchApiService; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.SearchResultDTO; @@ -55,9 +57,12 @@ public Response searchGet(Integer limit, Integer offset, String xWSO2Tenant, Str limit = limit != null ? limit : RestApiConstants.PAGINATION_LIMIT_DEFAULT; offset = offset != null ? offset : RestApiConstants.PAGINATION_OFFSET_DEFAULT; query = query == null ? "*" : query; - String organization = RestApiUtil.getOrganization(messageContext); try { + String superOrganization = RestApiUtil.getValidatedOrganization(messageContext); + OrganizationInfo orgInfo = RestApiUtil.getOrganizationInfo(messageContext); + orgInfo.setSuperOrganization(superOrganization); + if (!query.contains(":")) { query = (APIConstants.CONTENT_SEARCH_TYPE_PREFIX + ":" + query); } @@ -66,11 +71,21 @@ public Response searchGet(Integer limit, Integer offset, String xWSO2Tenant, Str APIConsumer apiConsumer = RestApiCommonUtil.getConsumer(username); Map result = null; // Extracting search queries for the recommendation system - apiConsumer.publishSearchQuery(query, username, organization); + apiConsumer.publishSearchQuery(query, username, superOrganization); + boolean isOrganizationSupportEnabled = APIUtil.isOrganizationAccessControlEnabled(); if (query.startsWith(APIConstants.CONTENT_SEARCH_TYPE_PREFIX)) { - result = apiConsumer.searchPaginatedContent(query, organization, offset, limit); + if (isOrganizationSupportEnabled) { + result = apiConsumer.searchPaginatedContent(query, orgInfo, offset, limit); + } else { + result = apiConsumer.searchPaginatedContent(query, superOrganization, offset, limit); + } } else { - result = apiConsumer.searchPaginatedAPIs(query, organization, offset, limit, null, null); + if (isOrganizationSupportEnabled) { + result = apiConsumer.searchPaginatedAPIs(query, orgInfo, offset, limit, null, null); + } else { + result = apiConsumer.searchPaginatedAPIs(query, superOrganization, offset, limit, null, + null); + } } ArrayList apis; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/ApplicationMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/ApplicationMappingUtil.java index 0531358de3b1..7f49b061f031 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/ApplicationMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/ApplicationMappingUtil.java @@ -28,6 +28,7 @@ import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationAttributeDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationAttributeListDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationDTO.VisibilityEnum; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationInfoDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApplicationListDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.PaginationDTO; @@ -64,6 +65,12 @@ public static ApplicationDTO fromApplicationtoDTO(Application application) throw .equals(application.getTokenType())) { applicationDTO.setTokenType(ApplicationDTO.TokenTypeEnum.valueOf(application.getTokenType())); } + if ((application.getSharedOrganization() == null) + || (APIConstants.DEFAULT_APP_SHARING_KEYWORD.equals(application.getSharedOrganization()))) { + applicationDTO.setVisibility(VisibilityEnum.PRIVATE); + } else { + applicationDTO.setVisibility(VisibilityEnum.SHARED_WITH_ORG); + } //todo: Uncomment when this is implemented /*List applicationKeyDTOs = new ArrayList<>(); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java index b5206110e7b4..c056ffe1be1f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java @@ -68,6 +68,7 @@ public SettingsDTO fromSettingstoDTO(Boolean isUserAvailable, Boolean moneatizat identityProviderDTO.setExternal(APIUtil.getIdentityProviderConfig() != null); settingsDTO.setIdentityProvider(identityProviderDTO); settingsDTO.setIsAnonymousModeEnabled(anonymousEnabled); + settingsDTO.setOrgAccessControlEnabled(APIUtil.isOrganizationAccessControlEnabled()); APIManagerConfiguration config = ServiceReferenceHolder.getInstance(). getAPIManagerConfigurationService().getAPIManagerConfiguration(); boolean enableChangePassword = diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/utils/APIUtils.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/utils/APIUtils.java index a88b927db7ab..7b8c9e00fe66 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/utils/APIUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/utils/APIUtils.java @@ -20,10 +20,12 @@ import org.wso2.carbon.apimgt.api.APIConsumer; import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.api.dto.KeyManagerConfigurationDTO; import org.wso2.carbon.apimgt.api.model.API; import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.api.model.Environment; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiCommonUtil; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIDefaultVersionURLsDTO; @@ -199,4 +201,21 @@ public static List extractEndpointURLs(APIProduct apiProduct return apiEndpointsList; } + + public static List filterAllowedKeyManagersForOrganizations( + List keymanagerConfigs, OrganizationInfo orgInfo) { + + List allowedList = new ArrayList(); + String organization = orgInfo.getOrganizationSelector(); + for (KeyManagerConfigurationDTO keyManagerConfigurationDTO : keymanagerConfigs) { + List allowedOrgs = keyManagerConfigurationDTO.getAllowedOrganizations(); + // Add to allowedList if no organizations are restricted or if the organization is allowed + if (allowedOrgs == null || allowedOrgs.isEmpty() || allowedOrgs.contains(organization)) { + allowedList.add(keyManagerConfigurationDTO); + } + + } + + return allowedList; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml index 993819c1a019..5e9e58d94d98 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml @@ -4399,6 +4399,11 @@ components: type: string readOnly: true example: 1651555310208 + visibility: + type: string + enum: + - PRIVATE + - SHARED_WITH_ORG ApplicationInfo: title: Application info object with basic application details type: object @@ -5587,6 +5592,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + orgAccessControlEnabled: + type: boolean + description: | + Is Organization-based access control configuration enabled + example: true userStorePasswordPattern: type: string description: The 'PasswordJavaRegEx' cofigured in the UserStoreManager diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/impl/OAuthOpaqueAuthenticatorImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/impl/OAuthOpaqueAuthenticatorImpl.java index 3b8a8d7ccd07..c3ecdb3d7b99 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/impl/OAuthOpaqueAuthenticatorImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/impl/OAuthOpaqueAuthenticatorImpl.java @@ -17,11 +17,15 @@ package org.wso2.carbon.apimgt.rest.api.util.impl; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.cxf.message.Message; +import org.json.JSONException; +import org.json.JSONObject; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; import org.wso2.carbon.apimgt.impl.RESTAPICacheConfiguration; import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO; import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; @@ -36,11 +40,14 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO; import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.UserRealm; +import org.wso2.carbon.user.core.UserStoreManager; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.carbon.apimgt.api.OAuthTokenInfo; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.rest.api.util.authenticators.AbstractOAuthAuthenticator; import java.util.HashMap; @@ -148,6 +155,10 @@ public boolean authenticate(Message message) throws APIManagementException { carbonContext.setUsername(username); message.put(RestApiConstants.AUTH_TOKEN_INFO, tokenInfo); message.put(RestApiConstants.SUB_ORGANIZATION, tenantDomain); + if (ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService() + .getAPIManagerConfiguration().getOrgAccessControl().isEnabled()) { + message.put(RestApiConstants.ORGANIZATION_INFO, getOrganizationInfo(tenantDomain, username)); + } if (!tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) { APIUtil.loadTenantConfigBlockingMode(tenantDomain); } @@ -236,4 +247,78 @@ protected String getConfigurationElementValue(String property) { return ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService().getAPIManagerConfiguration() .getFirstProperty(property); } + + public OrganizationInfo getOrganizationInfo(String tenantDomain, String username) { + OrganizationInfo orgInfo = new OrganizationInfo(); + orgInfo.setSuperOrganization(tenantDomain); + + Boolean isSuperTenant = true; + int tenantId = MultitenantConstants.SUPER_TENANT_ID; + APIManagerConfiguration config = ServiceReferenceHolder.getInstance(). + getAPIManagerConfigurationService().getAPIManagerConfiguration(); + String orgNameClaim = config.getOrgAccessControl().getOrgNameLocalClaim(); + String orgIdClaim = config.getOrgAccessControl().getOrgIdLocalClaim(); + String orgSelectorClaim = config.getOrgAccessControl().getOrgSelectorClaim(); + if (StringUtils.isBlank(orgNameClaim)) { + orgNameClaim = "http://wso2.org/claims/organization"; + } + if (StringUtils.isBlank(orgIdClaim)) { + orgIdClaim = "http://wso2.org/claims/organizationId"; + } + + String organization = null; + String organizationId = null; + String orgSelector = null; + String[] groupIdArray = null; + try { + if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) { + isSuperTenant = true; + } + + RealmService realmService = ServiceReferenceHolder.getInstance().getRealmService(); + + //if the user is not in the super tenant domain then find the domain name and tenant id. + if (!isSuperTenant) { + tenantDomain = MultitenantUtils.getTenantDomain(username); + tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager() + .getTenantId(tenantDomain); + } + + UserRealm realm = (UserRealm) realmService.getTenantUserRealm(tenantId); + UserStoreManager manager = realm.getUserStoreManager(); + organization = + manager.getUserClaimValue(MultitenantUtils.getTenantAwareUsername(username), orgNameClaim, null); + organizationId = + manager.getUserClaimValue(MultitenantUtils.getTenantAwareUsername(username), orgIdClaim, null); + if (StringUtils.isBlank(orgSelectorClaim)) { + orgSelector = organization; // default selector will be organization name + } else { + orgSelector = manager.getUserClaimValue(MultitenantUtils.getTenantAwareUsername(username), + orgSelectorClaim, null); + } + if (organization != null) { + if (organization.contains(",")) { + groupIdArray = organization.split(","); + for (int i = 0; i < groupIdArray.length; i++) { + groupIdArray[i] = groupIdArray[i].toString().trim(); + } + } else { + organization = organization.trim(); + groupIdArray = new String[] {organization}; + orgInfo.setName(organization); // check for multiple orgs + orgInfo.setId(organizationId); + orgInfo.setOrganizationSelector(orgSelector); + } + } else { + // If claim is null then returning a empty string + groupIdArray = new String[] {}; + } + } catch (JSONException e) { + log.error("Exception occured while trying to get group Identifier from login response", e); + } catch (org.wso2.carbon.user.api.UserStoreException e) { + log.error("Error while checking user existence for " + username, e); + } + + return orgInfo; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/auth/OAuthAuthenticationInterceptor.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/auth/OAuthAuthenticationInterceptor.java index df2c63886b41..f25cc2f5691e 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/auth/OAuthAuthenticationInterceptor.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/auth/OAuthAuthenticationInterceptor.java @@ -23,9 +23,14 @@ import org.apache.cxf.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; +import org.json.JSONException; +import org.json.JSONObject; import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.OAuthTokenInfo; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiCommonUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiConstants; @@ -37,6 +42,10 @@ import org.wso2.carbon.apimgt.rest.api.util.impl.OAuthOpaqueAuthenticatorImpl; import org.wso2.carbon.apimgt.rest.api.util.utils.JWTAuthenticationUtils; import org.wso2.carbon.apimgt.rest.api.util.utils.RestApiUtil; +import org.wso2.carbon.user.core.UserRealm; +import org.wso2.carbon.user.core.UserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import java.util.HashMap; import java.util.Map; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/utils/RestApiUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/utils/RestApiUtil.java index d0f025e61e94..0d6b97ad45cf 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/utils/RestApiUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/utils/RestApiUtil.java @@ -37,6 +37,7 @@ import org.wso2.carbon.apimgt.api.model.DuplicateAPIException; import org.wso2.carbon.apimgt.api.model.OAuthAppRequest; import org.wso2.carbon.apimgt.api.model.OAuthApplicationInfo; +import org.wso2.carbon.apimgt.api.model.OrganizationInfo; import org.wso2.carbon.apimgt.api.model.ResourceFile; import org.wso2.carbon.apimgt.api.model.Tier; import org.wso2.carbon.apimgt.impl.AMDefaultKeyManagerImpl; @@ -1298,6 +1299,20 @@ public static String getValidatedOrganization(MessageContext ctx) throws APIMana } return organization; } + + /** + * Method to extract the User organization + * @param ctx MessageContext + * @return organization + */ + + public static OrganizationInfo getOrganizationInfo(MessageContext ctx) throws APIManagementException { + OrganizationInfo organizationInfo = new OrganizationInfo(); + if (ctx.get(RestApiConstants.ORGANIZATION_INFO) != null) { + organizationInfo = (OrganizationInfo) ctx.get(RestApiConstants.ORGANIZATION_INFO); + } + return organizationInfo; + } /** @@ -1340,4 +1355,29 @@ public static String resolveOrganization (HashMap message) throws String organization = resolver.resolve(properties); return organization; } + + public static boolean isOrganizationVisibilityAllowed(String userName, String visibleOrgs, String userOrg) + throws APIManagementException { + boolean allowed = false; + + if (APIUtil.isOrganizationAccessControlEnabled()) { + String[] roles = APIUtil.getListOfRoles(APIUtil.getUserNameWithTenantSuffix(userName)); + if (Arrays.asList(roles).contains("admin")) { + return true; + } + if (StringUtils.isEmpty(visibleOrgs) || APIConstants.DEFAULT_VISIBLE_ORG.equals(visibleOrgs)) { + allowed = true; + } else { + List visibleOrgList = Arrays.asList(visibleOrgs.split(",")); + + if (visibleOrgList.contains(userOrg)) { + allowed = true; + } else { + allowed = false; + } + } + return allowed; + } + return true; + } } diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 index 81338d4f3788..a519bb4a8de2 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 @@ -105,6 +105,15 @@ + {% if apim.organization_based_access_control is defined %} + + {{apim.organization_based_access_control.enable}} + {{apim.organization_based_access_control.organization_name_local_claim}} + {{apim.organization_based_access_control.organization_id_local_claim}} + {{apim.organization_based_access_control.organization_selector_local_claim}} + + {% endif %} + diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql index 8c0ad159e94b..595e4ea45e22 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql @@ -1542,6 +1542,7 @@ CREATE TABLE IF NOT EXISTS AM_APPLICATION ( UUID VARCHAR(256), TOKEN_TYPE VARCHAR(10), ORGANIZATION VARCHAR(100), + SHARED_ORGANIZATION VARCHAR(100), FOREIGN KEY(SUBSCRIBER_ID) REFERENCES AM_SUBSCRIBER(SUBSCRIBER_ID) ON UPDATE CASCADE ON DELETE RESTRICT, PRIMARY KEY(APPLICATION_ID), UNIQUE (NAME,SUBSCRIBER_ID,ORGANIZATION), @@ -2138,6 +2139,20 @@ CREATE TABLE IF NOT EXISTS AM_KEY_MANAGER_PERMISSIONS ( FOREIGN KEY (KEY_MANAGER_UUID) REFERENCES AM_KEY_MANAGER(UUID) ON DELETE CASCADE ); +CREATE TABLE IF NOT EXISTS AM_KEY_MANAGER_ALLOWED_ORGS ( + KEY_MANAGER_UUID VARCHAR(50) NOT NULL, + ALLOWED_ORGANIZATIONS VARCHAR(50) NOT NULL, + PRIMARY KEY (KEY_MANAGER_UUID, ALLOWED_ORGANIZATIONS), + FOREIGN KEY (KEY_MANAGER_UUID) REFERENCES AM_KEY_MANAGER(UUID) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS AM_POLICY_ALLOWED_ORGS ( + ALLOWED_ORGS_ID INT NOT NULL AUTO_INCREMENT, + POLICY_UUID VARCHAR(50) NOT NULL, + ALLOWED_ORGANIZATIONS VARCHAR(50) NOT NULL, + PRIMARY KEY (ALLOWED_ORGS_ID) +); + -- AM_GW_PUBLISHED_API_DETAILS & AM_GW_API_ARTIFACTS are independent tables for Artifact synchronizer feature which -- -- should not have any referential integrity constraints with other tables in AM database-- CREATE TABLE IF NOT EXISTS AM_GW_PUBLISHED_API_DETAILS ( diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql index f82158dc982d..d13ac6b10ca9 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql @@ -1490,6 +1490,7 @@ CREATE TABLE IF NOT EXISTS AM_APPLICATION ( UUID VARCHAR(256), TOKEN_TYPE VARCHAR(10), ORGANIZATION VARCHAR(100), + SHARED_ORGANIZATION VARCHAR(100), FOREIGN KEY(SUBSCRIBER_ID) REFERENCES AM_SUBSCRIBER(SUBSCRIBER_ID) ON UPDATE CASCADE ON DELETE RESTRICT, PRIMARY KEY(APPLICATION_ID), UNIQUE (NAME,SUBSCRIBER_ID,ORGANIZATION), diff --git a/pom.xml b/pom.xml index a25205332a80..3ec735989f22 100644 --- a/pom.xml +++ b/pom.xml @@ -2031,7 +2031,7 @@ 4.9.11 - 4.8.36 + 4.8.40 4.7.221 4.1.0 @@ -2083,7 +2083,7 @@ 1.5.3 - 3.2.0 + 3.3.0 1.9.1 1.6.3