diff --git a/modules/distribution/product/src/main/assembly/bin.xml b/modules/distribution/product/src/main/assembly/bin.xml index 9f602e21f5..3b4ef81fb6 100644 --- a/modules/distribution/product/src/main/assembly/bin.xml +++ b/modules/distribution/product/src/main/assembly/bin.xml @@ -470,6 +470,7 @@ authenticationendpoint/basicauth.jsp + authenticationendpoint/EndpointConfig.properties authenticationendpoint/identifierauth.jsp authenticationendpoint/includes/cookie-policy-content.jsp authenticationendpoint/includes/header.jsp @@ -526,6 +527,7 @@ + accountrecoveryendpoint/RecoveryEndpointConfig.properties accountrecoveryendpoint/self-registration-complete.jsp accountrecoveryendpoint/password-recovery.jsp accountrecoveryendpoint/includes/header.jsp diff --git a/modules/distribution/product/src/main/extensions/basicauth.jsp b/modules/distribution/product/src/main/extensions/basicauth.jsp index 17914601ff..5d801ec01b 100644 --- a/modules/distribution/product/src/main/extensions/basicauth.jsp +++ b/modules/distribution/product/src/main/extensions/basicauth.jsp @@ -293,7 +293,7 @@ data-size="invisible" data-callback="onCompleted" data-action="login" - data-sitekey="<%=Encode.forHtmlContent(request.getParameter("reCaptchaKey"))%>" + data-sitekey="<%=Encode.forHtmlContent(reCaptchaKey)%>"> <% } diff --git a/modules/distribution/product/src/main/extensions/self-registration-username-request.jsp b/modules/distribution/product/src/main/extensions/self-registration-username-request.jsp index a263260d4a..11a2109a60 100644 --- a/modules/distribution/product/src/main/extensions/self-registration-username-request.jsp +++ b/modules/distribution/product/src/main/extensions/self-registration-username-request.jsp @@ -18,17 +18,25 @@ <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="org.owasp.encoder.Encode" %> +<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.ApiException" %> <%@ page import="org.wso2.carbon.identity.mgt.constants.SelfRegistrationStatusCodes" %> +<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.api.ReCaptchaApi" %> +<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.model.ReCaptchaProperties" %> <%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.IdentityManagementEndpointConstants" %> <%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.IdentityManagementServiceUtil" %> <%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.model.User" %> <%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.IdentityManagementEndpointUtil" %> +<%@ page import="org.wso2.carbon.identity.captcha.util.CaptchaUtil" %> +<%@ page import="java.util.Arrays" %> +<%@ page import="java.util.HashMap" %> <%@ page import="java.io.File" %> +<%@ page import="java.util.List" %> <%@ page import="java.util.Map" %> <%@ page import="java.util.Enumeration" %> <%@ taglib prefix="layout" uri="org.wso2.identity.apps.taglibs.layout.controller" %> + <% @@ -67,6 +75,23 @@ } else if (errorMsgObj != null) { errorMsg = errorMsgObj.toString(); } + ReCaptchaApi reCaptchaApi = new ReCaptchaApi(); + try { + ReCaptchaProperties reCaptchaProperties = reCaptchaApi.getReCaptcha(tenantDomain, true, "ReCaptcha", + "self-registration"); + if (reCaptchaProperties.getReCaptchaEnabled()) { + Map> headers = new HashMap<>(); + headers.put("reCaptcha", Arrays.asList(String.valueOf(true))); + headers.put("reCaptchaAPI", Arrays.asList(reCaptchaProperties.getReCaptchaAPI())); + headers.put("reCaptchaKey", Arrays.asList(reCaptchaProperties.getReCaptchaKey())); + IdentityManagementEndpointUtil.addReCaptchaHeaders(request, headers); + } + } catch (ApiException e) { + request.setAttribute("error", true); + request.setAttribute("errorMsg", e.getMessage()); + request.getRequestDispatcher("error.jsp").forward(request, response); + return; + } boolean skipSignUpEnableCheck = Boolean.parseBoolean(request.getParameter("skipsignupenablecheck")); %> @@ -75,6 +100,15 @@ layoutData.put("containerSize", "medium"); %> +<% + boolean reCaptchaEnabled = false; + if (request.getAttribute("reCaptcha") != null && "TRUE".equalsIgnoreCase((String) request.getAttribute("reCaptcha"))) { + reCaptchaEnabled = true; + } else if (request.getParameter("reCaptcha") != null && Boolean.parseBoolean(request.getParameter("reCaptcha"))) { + reCaptchaEnabled = true; + } +%> + @@ -87,6 +121,14 @@ <% } else { %> <% } %> + <% + if (reCaptchaEnabled) { + String reCaptchaAPI = CaptchaUtil.reCaptchaAPIURL(); + %> + + <% + } + %> @@ -151,6 +193,23 @@ <% } %> + <% + if (reCaptchaEnabled) { + String reCaptchaKey = CaptchaUtil.reCaptchaSiteKey(); + %> +
+
+
+
+ <% + } + %> +
@@ -209,6 +268,9 @@ } } }); + function onCompleted() { + $('#register').submit(); + } function goBack() { window.history.back(); } @@ -226,6 +288,16 @@ console.warn("Prevented a possible double submit event"); } else { e.preventDefault(); + <% + if (reCaptchaEnabled) { + %> + if (!grecaptcha.getResponse()) { + grecaptcha.execute(); + return; + } + <% + } + %> var userName = document.getElementById("username"); var normalizedUsername = userName.value.trim(); userName.value = normalizedUsername; diff --git a/modules/distribution/product/src/main/resources/conf/default.json b/modules/distribution/product/src/main/resources/conf/default.json index d4b057c09e..9895d593f3 100644 --- a/modules/distribution/product/src/main/resources/conf/default.json +++ b/modules/distribution/product/src/main/resources/conf/default.json @@ -458,5 +458,6 @@ "apim.analytics.properties.keystore_password": "$ref{keystore.primary.password}", "apim.analytics.properties.truststore_location": "${carbon.home}/repository/resources/security/$ref{truststore.file_name}", "apim.analytics.properties.truststore_password": "$ref{truststore.password}", - "tenant_mgt.disable_email_domain_validation": true + "tenant_mgt.disable_email_domain_validation": true, + "apim.jwt.use_kid_property": true } diff --git a/modules/distribution/product/src/main/resources/conf/templates/repository/conf/broker.xml.j2 b/modules/distribution/product/src/main/resources/conf/templates/repository/conf/broker.xml.j2 index 7de5426c14..75ed7f209f 100644 --- a/modules/distribution/product/src/main/resources/conf/templates/repository/conf/broker.xml.j2 +++ b/modules/distribution/product/src/main/resources/conf/templates/repository/conf/broker.xml.j2 @@ -101,6 +101,10 @@ This file is ciphertool compliant. Refer PRODUCT_HOME/repository/conf/security/c {{broker.transport.amqp.allow_shared_topic_subscriptions}} {{broker.transport.amqp.allow_strict_name_validation}} + + {{broker.transport.amqp.authorization}} + + diff --git a/modules/distribution/product/src/main/resources/conf/templates/repository/conf/tomcat/catalina-server.xml.j2 b/modules/distribution/product/src/main/resources/conf/templates/repository/conf/tomcat/catalina-server.xml.j2 index fc4500d1f3..a0adf6f4a7 100644 --- a/modules/distribution/product/src/main/resources/conf/templates/repository/conf/tomcat/catalina-server.xml.j2 +++ b/modules/distribution/product/src/main/resources/conf/templates/repository/conf/tomcat/catalina-server.xml.j2 @@ -94,7 +94,6 @@ - {% for valve in catalina.valves %} diff --git a/modules/distribution/product/src/main/resources/conf/templates/repository/conf/tomcat/context.xml.j2 b/modules/distribution/product/src/main/resources/conf/templates/repository/conf/tomcat/context.xml.j2 new file mode 100644 index 0000000000..6da9d49567 --- /dev/null +++ b/modules/distribution/product/src/main/resources/conf/templates/repository/conf/tomcat/context.xml.j2 @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + {% if web_app.control_access.enable is sameas true %} + + {% endif %} + + {% for class_name in web_app.listener.class_name %} + + {% endfor %} + + diff --git a/modules/distribution/product/src/main/startup-scripts/api-manager.bat b/modules/distribution/product/src/main/startup-scripts/api-manager.bat index ff08c75052..04fc8da6b8 100755 --- a/modules/distribution/product/src/main/startup-scripts/api-manager.bat +++ b/modules/distribution/product/src/main/startup-scripts/api-manager.bat @@ -203,7 +203,7 @@ set CARBON_CLASSPATH=".\lib\*";%CARBON_CLASSPATH% if %JAVA_VERSION% GEQ 110 set CARBON_CLASSPATH=".\lib\endorsed\*";%CARBON_CLASSPATH% if %JAVA_VERSION% LEQ 18 set JAVA_VER_BASED_OPTS=-Djava.endorsed.dirs=".\lib\endorsed";"%JAVA_HOME%\jre\lib\endorsed";"%JAVA_HOME%\lib\endorsed" -if %JAVA_VERSION% GEQ 110 set JAVA_VER_BASED_OPTS=--add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED +if %JAVA_VERSION% GEQ 110 set JAVA_VER_BASED_OPTS=--add-opens=java.base/sun.security.x509=ALL-UNNAMED --add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED set CMD_LINE_ARGS=-Xbootclasspath/a:%CARBON_XBOOTCLASSPATH% -Xms256m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="%CARBON_HOME%\repository\logs\heap-dump.hprof" set CMD_LINE_ARGS=%CMD_LINE_ARGS% -Dcom.sun.management.jmxremote -classpath %CARBON_CLASSPATH% %JAVA_OPTS% %JAVA_VER_BASED_OPTS% diff --git a/modules/distribution/product/src/main/startup-scripts/api-manager.sh b/modules/distribution/product/src/main/startup-scripts/api-manager.sh index 6acc994ce7..48f913573a 100755 --- a/modules/distribution/product/src/main/startup-scripts/api-manager.sh +++ b/modules/distribution/product/src/main/startup-scripts/api-manager.sh @@ -310,7 +310,7 @@ echo "Using Java memory options: $JVM_MEM_OPTS" JAVA_VER_BASED_OPTS="--add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED" if [ $java_version_formatted -ge 1700 ]; then - JAVA_VER_BASED_OPTS="$JAVA_VER_BASED_OPTS --add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED" + JAVA_VER_BASED_OPTS="$JAVA_VER_BASED_OPTS --add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/sun.security.x509=ALL-UNNAMED" fi while [ "$status" = "$START_EXIT_STATUS" ] diff --git a/modules/distribution/resources/api_templates/operation_policy_template.j2 b/modules/distribution/resources/api_templates/operation_policy_template.j2 index 15ff0d3f9b..1a09fdeaa9 100644 --- a/modules/distribution/resources/api_templates/operation_policy_template.j2 +++ b/modules/distribution/resources/api_templates/operation_policy_template.j2 @@ -1,6 +1,12 @@ - +{% if api_level_policies is defined %} +{% for policy in api_level_policies %} + {{policy}} +{% endfor %} +{% endif %} +{% if case_list is defined %} + {% for case in case_list %} @@ -9,10 +15,9 @@ {% endfor %} {% endfor %} - {% if fault_sequence %} - - - - {% endif %} +{% endif %} +{% if fault_sequence %} + +{% endif %} \ No newline at end of file diff --git a/modules/distribution/resources/api_templates/velocity_template.xml b/modules/distribution/resources/api_templates/velocity_template.xml index ec168cf1a3..4732d712ef 100644 --- a/modules/distribution/resources/api_templates/velocity_template.xml +++ b/modules/distribution/resources/api_templates/velocity_template.xml @@ -253,6 +253,7 @@ $in_sequences.get("$resource.getUriTemplate()").get($uri) #set( $roleRegion = $!{endpoint_config.get("amznRoleRegion")} ) #set( $resourceName = $!{resource.getAmznResourceName()} ) #set( $resourceTimeout = $!{resource.getAmznResourceTimeout()} ) + #set( $isContentEncodingEnabled = $!{resource.isAmznResourceContentEncoded()} ) #if( $accessKey != '' ) @@ -282,6 +283,9 @@ $in_sequences.get("$resource.getUriTemplate()").get($uri) #if( $resourceTimeout != '' ) #end + #if( $isContentEncodingEnabled != '' ) + + #end ## AWS Lambda: end diff --git a/modules/integration/tests-common/clients/publisher/.openapi-generator/publisher-api.yaml.sha256 b/modules/integration/tests-common/clients/publisher/.openapi-generator/publisher-api.yaml.sha256 index 18f39ec756..22bf2e2101 100644 --- a/modules/integration/tests-common/clients/publisher/.openapi-generator/publisher-api.yaml.sha256 +++ b/modules/integration/tests-common/clients/publisher/.openapi-generator/publisher-api.yaml.sha256 @@ -1 +1 @@ -da57e250c3772815419f3056fa0a9bf10bcb15fec37c7bed5676497509e04f78 \ No newline at end of file +e8e65082ff752153ae78c9fa8bbb657df3d59b3273fb70c9dcac53fc4f8915b3 \ No newline at end of file diff --git a/modules/integration/tests-common/clients/publisher/api/openapi.yaml b/modules/integration/tests-common/clients/publisher/api/openapi.yaml index 19ab6db8a4..b4ce30723f 100644 --- a/modules/integration/tests-common/clients/publisher/api/openapi.yaml +++ b/modules/integration/tests-common/clients/publisher/api/openapi.yaml @@ -16059,6 +16059,40 @@ components: value: value lifeCycleStatus: CREATED accessControl: NONE + apiPolicies: + request: + - policyVersion: v1 + policyId: policyId + policyName: policyName + parameters: + key: '{}' + - policyVersion: v1 + policyId: policyId + policyName: policyName + parameters: + key: '{}' + response: + - policyVersion: v1 + policyId: policyId + policyName: policyName + parameters: + key: '{}' + - policyVersion: v1 + policyId: policyId + policyName: policyName + parameters: + key: '{}' + fault: + - policyVersion: v1 + policyId: policyId + policyName: policyName + parameters: + key: '{}' + - policyVersion: v1 + policyId: policyId + policyName: policyName + parameters: + key: '{}' monetization: enabled: true properties: @@ -16349,6 +16383,8 @@ components: items: $ref: '#/components/schemas/MediationPolicy' type: array + apiPolicies: + $ref: '#/components/schemas/APIOperationPolicies' subscriptionAvailability: default: CURRENT_TENANT description: The subscription availability. Accepts one of the following. diff --git a/modules/integration/tests-common/clients/publisher/docs/APIDTO.md b/modules/integration/tests-common/clients/publisher/docs/APIDTO.md index 3499802ed9..1b635027e6 100644 --- a/modules/integration/tests-common/clients/publisher/docs/APIDTO.md +++ b/modules/integration/tests-common/clients/publisher/docs/APIDTO.md @@ -37,6 +37,7 @@ Name | Type | Description | Notes **visibleRoles** | **List<String>** | The user roles that are able to access the API in Developer Portal | [optional] **visibleTenants** | **List<String>** | | [optional] **mediationPolicies** | [**List<MediationPolicyDTO>**](MediationPolicyDTO.md) | | [optional] +**apiPolicies** | [**APIOperationPoliciesDTO**](APIOperationPoliciesDTO.md) | | [optional] **subscriptionAvailability** | [**SubscriptionAvailabilityEnum**](#SubscriptionAvailabilityEnum) | The subscription availability. Accepts one of the following. CURRENT_TENANT, ALL_TENANTS or SPECIFIC_TENANTS. | [optional] **subscriptionAvailableTenants** | **List<String>** | | [optional] **additionalProperties** | [**List<APIInfoAdditionalPropertiesDTO>**](APIInfoAdditionalPropertiesDTO.md) | Map of custom properties of API | [optional] diff --git a/modules/integration/tests-common/clients/publisher/src/gen/java/org/wso2/am/integration/clients/publisher/api/v1/dto/APIDTO.java b/modules/integration/tests-common/clients/publisher/src/gen/java/org/wso2/am/integration/clients/publisher/api/v1/dto/APIDTO.java index dc2c857bf8..be8c66c016 100644 --- a/modules/integration/tests-common/clients/publisher/src/gen/java/org/wso2/am/integration/clients/publisher/api/v1/dto/APIDTO.java +++ b/modules/integration/tests-common/clients/publisher/src/gen/java/org/wso2/am/integration/clients/publisher/api/v1/dto/APIDTO.java @@ -33,6 +33,7 @@ import org.wso2.am.integration.clients.publisher.api.v1.dto.APIInfoAdditionalPropertiesMapDTO; import org.wso2.am.integration.clients.publisher.api.v1.dto.APIMaxTpsDTO; import org.wso2.am.integration.clients.publisher.api.v1.dto.APIMonetizationInfoDTO; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIOperationPoliciesDTO; import org.wso2.am.integration.clients.publisher.api.v1.dto.APIOperationsDTO; import org.wso2.am.integration.clients.publisher.api.v1.dto.APIScopeDTO; import org.wso2.am.integration.clients.publisher.api.v1.dto.APIServiceInfoDTO; @@ -328,6 +329,10 @@ public VisibilityEnum read(final JsonReader jsonReader) throws IOException { @SerializedName(SERIALIZED_NAME_MEDIATION_POLICIES) private List mediationPolicies = null; + public static final String SERIALIZED_NAME_API_POLICIES = "apiPolicies"; + @SerializedName(SERIALIZED_NAME_API_POLICIES) + private APIOperationPoliciesDTO apiPolicies; + /** * The subscription availability. Accepts one of the following. CURRENT_TENANT, ALL_TENANTS or SPECIFIC_TENANTS. */ @@ -1284,6 +1289,29 @@ public void setMediationPolicies(List mediationPolicies) { } + public APIDTO apiPolicies(APIOperationPoliciesDTO apiPolicies) { + + this.apiPolicies = apiPolicies; + return this; + } + + /** + * Get apiPolicies + * @return apiPolicies + **/ + @javax.annotation.Nullable + @ApiModelProperty(value = "") + + public APIOperationPoliciesDTO getApiPolicies() { + return apiPolicies; + } + + + public void setApiPolicies(APIOperationPoliciesDTO apiPolicies) { + this.apiPolicies = apiPolicies; + } + + public APIDTO subscriptionAvailability(SubscriptionAvailabilityEnum subscriptionAvailability) { this.subscriptionAvailability = subscriptionAvailability; @@ -1899,6 +1927,7 @@ public boolean equals(Object o) { Objects.equals(this.visibleRoles, API.visibleRoles) && Objects.equals(this.visibleTenants, API.visibleTenants) && Objects.equals(this.mediationPolicies, API.mediationPolicies) && + Objects.equals(this.apiPolicies, API.apiPolicies) && Objects.equals(this.subscriptionAvailability, API.subscriptionAvailability) && Objects.equals(this.subscriptionAvailableTenants, API.subscriptionAvailableTenants) && Objects.equals(this.additionalProperties, API.additionalProperties) && @@ -1928,7 +1957,7 @@ public boolean equals(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, transport, tags, policies, apiThrottlingPolicy, authorizationHeader, securityScheme, maxTps, visibility, visibleRoles, visibleTenants, mediationPolicies, subscriptionAvailability, subscriptionAvailableTenants, additionalProperties, additionalPropertiesMap, monetization, accessControl, accessControlRoles, businessInformation, corsConfiguration, websubSubscriptionConfiguration, workflowStatus, createdTime, lastUpdatedTimestamp, lastUpdatedTime, endpointConfig, endpointImplementationType, scopes, operations, threatProtectionPolicies, categories, keyManagers, serviceInfo, advertiseInfo, gatewayVendor, asyncTransportProtocols); + return Objects.hash(id, name, description, context, version, provider, lifeCycleStatus, wsdlInfo, wsdlUrl, responseCachingEnabled, cacheTimeout, hasThumbnail, isDefaultVersion, isRevision, revisionedApiId, revisionId, enableSchemaValidation, enableSubscriberVerification, type, audience, transport, tags, policies, apiThrottlingPolicy, authorizationHeader, securityScheme, maxTps, visibility, visibleRoles, visibleTenants, mediationPolicies, apiPolicies, subscriptionAvailability, subscriptionAvailableTenants, additionalProperties, additionalPropertiesMap, monetization, accessControl, accessControlRoles, businessInformation, corsConfiguration, websubSubscriptionConfiguration, workflowStatus, createdTime, lastUpdatedTimestamp, lastUpdatedTime, endpointConfig, endpointImplementationType, scopes, operations, threatProtectionPolicies, categories, keyManagers, serviceInfo, advertiseInfo, gatewayVendor, asyncTransportProtocols); } @@ -1967,6 +1996,7 @@ public String toString() { sb.append(" visibleRoles: ").append(toIndentedString(visibleRoles)).append("\n"); sb.append(" visibleTenants: ").append(toIndentedString(visibleTenants)).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"); sb.append(" subscriptionAvailableTenants: ").append(toIndentedString(subscriptionAvailableTenants)).append("\n"); sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); diff --git a/modules/integration/tests-common/clients/publisher/src/main/resources/publisher-api.yaml b/modules/integration/tests-common/clients/publisher/src/main/resources/publisher-api.yaml index 261ee78cbf..de67456fcb 100644 --- a/modules/integration/tests-common/clients/publisher/src/main/resources/publisher-api.yaml +++ b/modules/integration/tests-common/clients/publisher/src/main/resources/publisher-api.yaml @@ -8707,6 +8707,12 @@ components: Name of the Authorization header used for invoking the API. If it is not set, Authorization header name specified in tenant or system level will be used. example: Authorization + apiKeyHeader: + type: string + pattern: '(^[^~!@#;:%^*()+={}|\\<>"'',&$\s+]*$)' + description: | + Name of the API key header used for invoking the API. If it is not set, default value `apiKey` will be used. + example: apiKey securityScheme: type: array description: | @@ -8756,6 +8762,8 @@ components: type: fault items: $ref: '#/components/schemas/MediationPolicy' + apiPolicies: + $ref: '#/components/schemas/APIOperationPolicies' subscriptionAvailability: type: string description: The subscription availability. Accepts one of the following. @@ -9352,6 +9360,12 @@ components: Name of the Authorization header used for invoking the API. If it is not set, Authorization header name specified in tenant or system level will be used. example: Authorization + apiKeyHeader: + type: string + pattern: '(^[^~!@#;:%^*()+={}|\\<>"'',&$\s+]*$)' + description: | + Name of the API key header used for invoking the API. If it is not set, default value `apiKey` will be used. + example: apiKey securityScheme: type: array description: | diff --git a/modules/integration/tests-common/integration-test-utils/src/main/java/org/wso2/am/integration/test/impl/RestAPIStoreImpl.java b/modules/integration/tests-common/integration-test-utils/src/main/java/org/wso2/am/integration/test/impl/RestAPIStoreImpl.java index e77518ebfa..3ff881f918 100644 --- a/modules/integration/tests-common/integration-test-utils/src/main/java/org/wso2/am/integration/test/impl/RestAPIStoreImpl.java +++ b/modules/integration/tests-common/integration-test-utils/src/main/java/org/wso2/am/integration/test/impl/RestAPIStoreImpl.java @@ -1737,6 +1737,35 @@ public SubscriptionDTO subscribeToAPI(String apiID, String appID, String tier,St return subscriptionResponse.getData(); } + /** + * Update subscription to an API of a specific tenant + * + * @param apiID API ID + * @param appID Application ID + * @param existingTier Existing subscription Tier + * @param requestedTier Requested subscription Tier + * @param subscriptionStatus subscription status + * @param subscriptionId Subscription ID + * @param xWso2Tenant Tenant Domain + * @return SubscriptionDTO + * @throws ApiException If an API exception occurs. + */ + public SubscriptionDTO updateSubscriptionToAPI(String apiID, String appID, String existingTier, + String requestedTier, SubscriptionDTO.StatusEnum subscriptionStatus, String subscriptionId, + String xWso2Tenant) throws ApiException, APIManagerIntegrationTestException { + + SubscriptionDTO subscription = new SubscriptionDTO(); + subscription.setApplicationId(appID); + subscription.setApiId(apiID); + subscription.setThrottlingPolicy(existingTier); + subscription.setRequestedThrottlingPolicy(requestedTier); + subscription.setStatus(subscriptionStatus); + SubscriptionDTO subscriptionUpdate = subscriptionIndividualApi.subscriptionsSubscriptionIdPut( + subscriptionId, subscription, xWso2Tenant); + waitUntilSubscriptionAvailableInGateway(subscriptionUpdate); + return subscriptionUpdate; + } + private void waitUntilSubscriptionAvailableInGateway(SubscriptionDTO subscribedDto) throws APIManagerIntegrationTestException { if (Boolean.parseBoolean(disableVerification)){ diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/crossSubscription/CrossTenantSubscriptionUpdateTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/crossSubscription/CrossTenantSubscriptionUpdateTestCase.java new file mode 100644 index 0000000000..7c9ac76534 --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/crossSubscription/CrossTenantSubscriptionUpdateTestCase.java @@ -0,0 +1,157 @@ +/* + *Copyright (c) 2023, 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.am.integration.tests.crossSubscription; + +import org.apache.commons.lang3.StringUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.am.integration.clients.admin.ApiException; +import org.wso2.am.integration.clients.store.api.v1.dto.*; +import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants; +import org.wso2.am.integration.test.utils.bean.APILifeCycleAction; +import org.wso2.am.integration.test.utils.bean.APIRequest; +import org.wso2.am.integration.tests.api.lifecycle.APIManagerLifecycleBaseTest; +import org.wso2.carbon.automation.engine.annotations.ExecutionEnvironment; +import org.wso2.carbon.automation.engine.annotations.SetEnvironment; +import org.wso2.carbon.automation.engine.context.TestUserMode; +import org.wso2.carbon.automation.test.utils.http.client.HttpResponse; +import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.io.File; +import java.net.URL; +import java.util.ArrayList; + +import static org.wso2.am.integration.clients.publisher.api.v1.dto.APIDTO.SubscriptionAvailabilityEnum.ALL_TENANTS; + +@SetEnvironment(executionEnvironments = { ExecutionEnvironment.STANDALONE }) +public class CrossTenantSubscriptionUpdateTestCase extends APIManagerLifecycleBaseTest { + private ServerConfigurationManager serverConfigurationManager; + private String apiId1; + private final String apiName1 = "Test1"; + private final String apiVersion1 = "1.0.0"; + private final String apiContext1 = "/test1"; + private String apiId2; + private final String apiName2 = "Test2"; + private final String apiVersion2 = "1.0.0"; + private final String apiContext2 = "/test2"; + + private final String apiEndpoint1 = "http://localhost:9443"; + private final String apiEndpoint2 = "http://localhost:9444"; + private final String tenant3ApplicationName = "TestApp"; + private ApplicationDTO tenant3Application; + private ApplicationKeyDTO tenant3AppTenant3Store; + private String tenant1Domain; + private String tenant2Domain; + private final String errorMessageKeyGeneration = "Error occurred while generating keys"; + + @BeforeClass(alwaysRun = true) + public void setEnvironment() throws Exception { + super.init(TestUserMode.SUPER_TENANT_ADMIN); + serverConfigurationManager = new ServerConfigurationManager(gatewayContextWrk); + serverConfigurationManager.applyConfiguration(new File(getAMResourceLocation() + + File.separator + "configFiles" + File.separator + "cross-tenant" + File.separator + "deployment.toml")); + APIRequest apiRequest1 = new APIRequest(apiName1, apiContext1, new URL(apiEndpoint1)); + apiRequest1.setVersion(apiVersion1); + apiRequest1.setTier(APIMIntegrationConstants.API_TIER.GOLD); + apiRequest1.setTiersCollection(APIMIntegrationConstants.API_TIER.GOLD + "," + APIMIntegrationConstants.API_TIER.BRONZE); + apiRequest1.setSubscriptionAvailability(ALL_TENANTS.toString()); + HttpResponse response = restAPIPublisher.addAPI(apiRequest1); + apiId1 = response.getData(); + restAPIPublisher.changeAPILifeCycleStatus(apiId1, APILifeCycleAction.PUBLISH.getAction()); + tenant1Domain = MultitenantUtils.getTenantDomain(user.getUserName()); + + super.init(TestUserMode.TENANT_ADMIN); + + APIRequest apiRequest2 = new APIRequest(apiName2, apiContext2, new URL(apiEndpoint2)); + apiRequest2.setVersion(apiVersion2); + apiRequest2.setTier(APIMIntegrationConstants.API_TIER.GOLD); + apiRequest2.setTiersCollection(APIMIntegrationConstants.API_TIER.GOLD + "," + APIMIntegrationConstants.API_TIER.BRONZE); + apiRequest2.setSubscriptionAvailability(ALL_TENANTS.toString()); + apiRequest2.setProvider(user.getUserName()); + HttpResponse response2 = restAPIPublisher.addAPI(apiRequest2); + apiId2 = response2.getData(); + restAPIPublisher.changeAPILifeCycleStatus(apiId2, APILifeCycleAction.PUBLISH.getAction()); + tenant2Domain = MultitenantUtils.getTenantDomain(user.getUserName()); + // tenant1 :carbon.super, tenant2 :wso2.com + Assert.assertNotEquals(tenant1Domain, tenant2Domain); + } + + @Test(description = "Create new application and generate access token using an already subscribed application") + public void testCreateNewApplicationAndGenerateTokenSubscribedApplication() throws Exception { + + super.init(TestUserMode.TENANT_EMAIL_USER); + + tenant3Application = restAPIStore.addApplication(tenant3ApplicationName, + APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED, + StringUtils.EMPTY, StringUtils.EMPTY); + SubscriptionDTO subscriptionDTO1 = restAPIStore.subscribeToAPI(apiId1, tenant3Application.getApplicationId(), + APIMIntegrationConstants.API_TIER.GOLD, tenant1Domain); + ArrayList grantTypes = new ArrayList<>(); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL); + restAPIAdmin.getKeyManagers(); // Due to the issue: https://github.com/wso2/product-apim/issues/12634 + tenant3AppTenant3Store = restAPIStore.generateKeys(tenant3Application.getApplicationId(), + APIMIntegrationConstants.DEFAULT_TOKEN_VALIDITY_TIME, + StringUtils.EMPTY, + ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, + null, grantTypes); + Assert.assertNotNull(tenant3AppTenant3Store, errorMessageKeyGeneration); + + // subscribe to the other API + SubscriptionDTO subscriptionDTO2 = restAPIStore.subscribeToAPI(apiId2, tenant3Application.getApplicationId(), + APIMIntegrationConstants.API_TIER.GOLD, tenant2Domain); + + restAPIStore.updateSubscriptionToAPI(apiId2, tenant3Application.getApplicationId(), APIMIntegrationConstants.API_TIER.GOLD, + APIMIntegrationConstants.API_TIER.BRONZE, SubscriptionDTO.StatusEnum.UNBLOCKED, subscriptionDTO2.getSubscriptionId(), tenant2Domain); + + verifyTenantDomainInWorkflowsTable(apiName2, tenant2Domain); + + restAPIStore.updateSubscriptionToAPI(apiId1, tenant3Application.getApplicationId(), APIMIntegrationConstants.API_TIER.GOLD, + APIMIntegrationConstants.API_TIER.BRONZE, SubscriptionDTO.StatusEnum.UNBLOCKED, subscriptionDTO1.getSubscriptionId(), tenant1Domain); + + verifyTenantDomainInWorkflowsTable(apiName1, tenant1Domain); + } + + private void verifyTenantDomainInWorkflowsTable (String apiName, String tenantDomain) throws JSONException, ApiException { + org.wso2.am.integration.test.HttpResponse workflowsResponse = restAPIAdmin.getWorkflows(null); + Assert.assertNotNull(workflowsResponse); + JSONObject workflowRespObj = new JSONObject(workflowsResponse.getData()); + JSONArray arr = (JSONArray) workflowRespObj.get("list"); + + for (int i = 0; i < arr.length(); i++) { + JSONObject listItem = (JSONObject) arr.get(i); + JSONObject properties = (JSONObject) listItem.get("properties"); + if (properties.has("apiName") && apiName.equals(properties.get("apiName"))) { + Assert.assertEquals(listItem.get("tenantDomain"), tenantDomain); + } + } + } + + @AfterClass(alwaysRun = true) + public void destroy() throws Exception { + restAPIStore.deleteApplication(tenant3Application.getApplicationId()); + serverConfigurationManager.restoreToLastConfiguration(); + } +} + diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CORSHeadersTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CORSHeadersTestCase.java index 0d554a13f8..c249f6a082 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CORSHeadersTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CORSHeadersTestCase.java @@ -83,7 +83,7 @@ public class CORSHeadersTestCase extends APIManagerLifecycleBaseTest { private static final String ACCESS_CONTROL_ALLOW_METHODS_HEADER_VALUE = "DELETE,POST,PUT,PATCH,GET"; private static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers"; private static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER_VALUE - = "authorization,Access-Control-Allow-Origin,Content-Type,SOAPAction,Authorization"; + = "authorization,Access-Control-Allow-Origin,Content-Type,SOAPAction,Authorization,ApiKey"; private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials"; private String accessToken; diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CustomHeaderTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CustomHeaderTestCase.java index 9648c1e3bf..f0c066c44e 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CustomHeaderTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/header/CustomHeaderTestCase.java @@ -23,6 +23,8 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.APIKeyDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyGenerateRequestDTO; @@ -38,6 +40,7 @@ import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import static org.wso2.am.integration.tests.restapi.RESTAPITestConstants.APPLICATION_JSON_CONTENT; import static org.wso2.am.integration.tests.restapi.RESTAPITestConstants.AUTHORIZATION_KEY; @@ -46,24 +49,23 @@ import java.net.URL; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class CustomHeaderTestCase extends APIManagerLifecycleBaseTest { private ServerConfigurationManager serverConfigurationManager; private final String CUSTOM_AUTHORIZATION_HEADER = "Test-Custom-Header"; + private final String DEFAULT_API_KEY_HEADER = "ApiKey"; + private final String CUSTOM_API_KEY_HEADER = "Custom-ApiKey-Header"; private final String API1_NAME = "CustomAuthHeaderTestAPI1"; private final String API1_CONTEXT = "customAuthHeaderTest1"; private final String API1_VERSION = "1.0.0"; - private final String APPLICATION1_NAME = "CustomHeaderTest-Application"; private final String API_END_POINT_METHOD = "customers/123"; - - private final String API2_NAME = "CustomAuthHeaderTestAPI2"; - private final String API2_CONTEXT = "customAuthHeaderTest2"; - private final String API2_VERSION = "1.0.0"; private String accessToken; private String applicationId; private String apiId; + String invocationUrl; @Factory(dataProvider = "userModeDataProvider") public CustomHeaderTestCase(TestUserMode userMode) { @@ -94,22 +96,25 @@ public void setEnvironment() throws Exception { APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED, ApplicationDTO.TokenTypeEnum.JWT); applicationId = applicationResponse.getData(); - } - - @Test(groups = {"wso2.am"}, description = "Set a customer Auth header for all APIs in the system. (Test ID: 3.1.1.5, 3.1.1.14)") - public void testSystemWideCustomAuthHeader() throws Exception { - - APIIdentifier apiIdentifier1 = new APIIdentifier(user.getUserName(), API1_NAME, API1_VERSION); + // Create API String url = getGatewayURLHttp() + "jaxrs_basic/services/customers/customerservice"; APIRequest apiRequest = new APIRequest(API1_NAME, API1_CONTEXT, new URL(url), new URL(url)); apiRequest.setVersion(API1_VERSION); apiRequest.setProvider(user.getUserName()); apiRequest.setTiersCollection(TIER_UNLIMITED); - String invocationUrl = getAPIInvocationURLHttps(API1_CONTEXT, API1_VERSION) + "/" + API_END_POINT_METHOD; + List securitySchemes = new ArrayList<>(); + securitySchemes.add("oauth2"); + securitySchemes.add("api_key"); + apiRequest.setSecurityScheme(securitySchemes); + invocationUrl = getAPIInvocationURLHttps(API1_CONTEXT, API1_VERSION) + "/" + API_END_POINT_METHOD; apiId = createPublishAndSubscribeToAPIUsingRest(apiRequest, restAPIPublisher, restAPIStore, applicationId, APIMIntegrationConstants.API_TIER.UNLIMITED); waitForAPIDeploymentSync(user.getUserName(), API1_NAME, API1_VERSION, APIMIntegrationConstants.IS_API_EXISTS); + } + + @Test(groups = {"wso2.am"}, description = "Set a customer Auth header for all APIs in the system. (Test ID: 3.1.1.5, 3.1.1.14)") + public void testSystemWideCustomAuthHeader() throws Exception { //get access token ArrayList grantTypes = new ArrayList<>(); @@ -138,6 +143,69 @@ public void testSystemWideCustomAuthHeader() throws Exception { "Response code mismatched"); } + @Test(groups = {"wso2.am"}, description = "Invoke an API with default API Key header", + dependsOnMethods = "testSystemWideCustomAuthHeader") + public void testInvokeAPIWIthDefaultApiKeyHeader() throws Exception { + + // Genarate API Keys for the application + APIKeyDTO apiKeyDTO = restAPIStore + .generateAPIKeys(applicationId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION.toString(), + -1, null, null); + assertNotNull(apiKeyDTO, "API Key generation failed"); + String apiKey = apiKeyDTO.getApikey(); + + // Test whether a request can be made with the default API Key header + Map requestHeaders1 = new HashMap<>(); + requestHeaders1.put("accept", APPLICATION_JSON_CONTENT); + requestHeaders1.put(DEFAULT_API_KEY_HEADER, apiKey); + HttpResponse apiResponse1 = HttpRequestUtil.doGet(invocationUrl, requestHeaders1); + assertEquals(apiResponse1.getResponseCode(), Response.Status.OK.getStatusCode(), + "Response code mismatched"); + + // Test whether the 401 Unauthorized Response is returned with incorrect API Key header + Map requestHeaders2 = new HashMap<>(); + requestHeaders2.put("accept", APPLICATION_JSON_CONTENT); + requestHeaders2.put(CUSTOM_API_KEY_HEADER, apiKey); + HttpResponse apiResponse2 = HttpRequestUtil.doGet(invocationUrl, requestHeaders2); + assertEquals(apiResponse2.getResponseCode(), Response.Status.UNAUTHORIZED.getStatusCode(), + "Response code mismatched"); + } + + @Test(groups = {"wso2.am"}, description = "Invoke an API with custom API Key header", + dependsOnMethods = "testInvokeAPIWIthDefaultApiKeyHeader") + public void testInvokeAPIWIthCustomApiKeyHeader() throws Exception { + + // Genarate API Keys for the application + APIKeyDTO apiKeyDTO = restAPIStore + .generateAPIKeys(applicationId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION.toString(), + -1, null, null); + assertNotNull(apiKeyDTO, "API Key generation failed"); + String apiKey = apiKeyDTO.getApikey(); + + // Update the API with custom API Key header + APIDTO apidto = restAPIPublisher.getAPIByID(apiId); + apidto.setApiKeyHeader(CUSTOM_API_KEY_HEADER); + restAPIPublisher.updateAPI(apidto); + createAPIRevisionAndDeployUsingRest(apiId, restAPIPublisher); + Thread.sleep(10000); + + // Test whether a request can be made with the custom API Key header + Map requestHeaders1 = new HashMap<>(); + requestHeaders1.put("accept", APPLICATION_JSON_CONTENT); + requestHeaders1.put(CUSTOM_API_KEY_HEADER, apiKey); + HttpResponse apiResponse1 = HttpRequestUtil.doGet(invocationUrl, requestHeaders1); + assertEquals(apiResponse1.getResponseCode(), Response.Status.OK.getStatusCode(), + "Response code mismatched"); + + // Test whether the 401 Unauthorized Response is returned with default API Key header + Map requestHeaders2 = new HashMap<>(); + requestHeaders2.put("accept", APPLICATION_JSON_CONTENT); + requestHeaders2.put(DEFAULT_API_KEY_HEADER, apiKey); + HttpResponse apiResponse2 = HttpRequestUtil.doGet(invocationUrl, requestHeaders2); + assertEquals(apiResponse2.getResponseCode(), Response.Status.UNAUTHORIZED.getStatusCode(), + "Response code mismatched"); + } + @AfterClass(alwaysRun = true) public void destroy() throws Exception { SubscriptionListDTO subsDTO = restAPIStore.getAllSubscriptionsOfApplication(applicationId); diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java index fc3dcb5552..adb6dbbc89 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java @@ -49,13 +49,20 @@ public static void verifySignature(Header jwtheader) throws UnsupportedEncodingE * verify JWT Header * * @param decodedJWTHeaderString decoded JWT Header value + * @param jwksKidClaim kid claim in JWKS endpoint * @throws JSONException if JSON payload is malformed */ - public static void verifyJWTHeader(String decodedJWTHeaderString) throws JSONException { + public static void verifyJWTHeader(String decodedJWTHeaderString, String jwksKidClaim) throws JSONException { JSONObject jsonHeaderObject = new JSONObject(decodedJWTHeaderString); Assert.assertEquals(jsonHeaderObject.getString("typ"), "JWT"); Assert.assertEquals(jsonHeaderObject.getString("alg"), "RS256"); - Assert.assertFalse(jsonHeaderObject.has("kid")); + + // Verify kid claim: check if kid claim in JWT header match with that of JWKS endpoint + Assert.assertTrue(jsonHeaderObject.has("kid")); + if (jwksKidClaim != null) { + Assert.assertEquals(jsonHeaderObject.getString("kid"), jwksKidClaim, "kid claim in JWT header " + + "does not match with that of JWKS endpoint"); + } } /** diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java index dcb6506b30..8ede9d48b6 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java @@ -28,6 +28,7 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import org.testng.Assert; @@ -76,6 +77,7 @@ import javax.ws.rs.core.Response; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.AssertJUnit.assertTrue; @@ -107,6 +109,7 @@ public class JWTTestCase extends APIManagerLifecycleBaseTest { URL tokenEndpointURL; private String tokenURL; private String identityLoginURL; + private String jwksKidClaim; private final String CALLBACK_URL = "https://localhost:9443/store/"; @BeforeClass(alwaysRun = true) @@ -191,6 +194,16 @@ public void setEnvironment() throws Exception { APIMIntegrationConstants.IS_API_EXISTS); waitForAPIDeploymentSync(user.getUserName(), api2Request.getName(), api2Request.getVersion(), APIMIntegrationConstants.IS_API_EXISTS); + + // Invoke JWKS endpoint and retrieve kid claim to validate backend JWT + HttpClient httpclient = HttpClientBuilder.create().build(); + HttpGet jwksGet = new HttpGet(getAPIInvocationURLHttp("jwks")); + HttpResponse jwksResponse = httpclient.execute(jwksGet); + assertEquals(jwksResponse.getStatusLine().getStatusCode(), HTTP_RESPONSE_CODE_OK, + "Invocation fails for JWKS GET request"); + String jwksResponseString = EntityUtils.toString(jwksResponse.getEntity(), "UTF-8"); + JSONObject jwksResponseObject = new JSONObject(jwksResponseString); + jwksKidClaim = jwksResponseObject.getJSONArray("keys").getJSONObject(0).getString("kid"); } @Test(groups = {"wso2.am"}, description = "Backend JWT Token Generation for Oauth Based App") @@ -225,7 +238,7 @@ public void testEnableJWTAndClaimsForOauthApp() throws Exception { //Do the signature verification for super tenant as tenant key store not there accessible BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); log.info("JWT Received ==" + jsonObject.toString()); //Validate expiry time @@ -273,7 +286,7 @@ public void testEnableJWTAndClaimsForJWTApp() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims @@ -341,7 +354,7 @@ public void testEnableJWTAndClaimsForAPIKeyApp() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims @@ -386,7 +399,7 @@ public void testBackendJWTWithClientCredentialsGrant() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims @@ -434,7 +447,7 @@ public void testBackendJWTWithAuthCodeGrant() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java index b175554f07..ac8253b4bf 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java @@ -156,7 +156,7 @@ public void testEnableJWTAndClaimsForOauthApp() throws Exception { JSONObject jsonHeaderObject = new JSONObject(decodedJWTHeaderString); Assert.assertEquals(jsonHeaderObject.getString("typ"), "JWT"); Assert.assertEquals(jsonHeaderObject.getString("alg"), "RS256"); - Assert.assertFalse(jsonHeaderObject.has("kid")); + Assert.assertTrue(jsonHeaderObject.has("kid")); JSONObject jsonObject = new JSONObject(decodedJWTString); log.info("JWT Received ==" + jsonObject.toString()); // check default claims @@ -212,7 +212,7 @@ public void testEnableJWTAndClaimsForJWTApp() throws Exception { JSONObject jsonHeaderObject = new JSONObject(decodedJWTHeaderString); Assert.assertEquals(jsonHeaderObject.getString("typ"), "JWT"); Assert.assertEquals(jsonHeaderObject.getString("alg"), "RS256"); - Assert.assertFalse(jsonHeaderObject.has("kid")); + Assert.assertTrue(jsonHeaderObject.has("kid")); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/SharedScopeTestWithRestart.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/SharedScopeTestWithRestart.java new file mode 100644 index 0000000000..22c059377d --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/SharedScopeTestWithRestart.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023, 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.am.integration.tests.other; + +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import org.wso2.am.integration.clients.publisher.api.v1.dto.ScopeDTO; +import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants; +import org.wso2.am.integration.tests.api.lifecycle.APIManagerLifecycleBaseTest; +import org.wso2.carbon.automation.engine.context.AutomationContext; +import org.wso2.carbon.automation.engine.context.TestUserMode; +import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class SharedScopeTestWithRestart extends APIManagerLifecycleBaseTest { + + private String sharedScopeName = "TestSharedScopeWithRestart"; + private String sharedScopeDisplayName = "Test Shared Scope with Restart"; + private String description = "This is a test shared scope with Restart"; + private String updatedDescription = "This is a updated test shared scope with Restart"; + private String updatedDescription1 = "This is a updated test shared scope with Restart(2)"; + private String updatedDescription2 = "This is a updated test shared scope with Restart(3)"; + private List roles = new ArrayList<>(); + private String sharedScopeId; + private ServerConfigurationManager serverConfigurationManager; + + @Factory(dataProvider = "userModeDataProvider") + public SharedScopeTestWithRestart(TestUserMode userMode) { + this.userMode = userMode; + } + + @DataProvider + public static Object[][] userModeDataProvider() { + return new Object[][] { new Object[] { TestUserMode.SUPER_TENANT_ADMIN }}; + } + + @BeforeClass(alwaysRun = true) + public void setEnvironment() throws Exception { + super.init(userMode); + superTenantKeyManagerContext = new AutomationContext(APIMIntegrationConstants.AM_PRODUCT_GROUP_NAME, + APIMIntegrationConstants.AM_KEY_MANAGER_INSTANCE, + TestUserMode.SUPER_TENANT_ADMIN); + serverConfigurationManager = new ServerConfigurationManager(superTenantKeyManagerContext); + serverConfigurationManager.applyConfiguration(new File( + getAMResourceLocation() + File.separator + "scopes" + + File.separator + "deployment.toml")); + } + + @Test(groups = { "wso2.am" }, description = "Test add shared scope") + public void testAddSharedScope() throws Exception { + ScopeDTO scopeDTO = new ScopeDTO(); + scopeDTO.setName(sharedScopeName); + scopeDTO.setDisplayName(sharedScopeDisplayName); + scopeDTO.setDescription(description); + + roles.add("Internal/publisher"); + roles.add("admin"); + scopeDTO.setBindings(roles); + + ScopeDTO addedScopeDTO = restAPIPublisher.addSharedScope(scopeDTO); + sharedScopeId = addedScopeDTO.getId(); + Assert.assertNotNull(sharedScopeId, "The scope ID cannot be null or empty"); + } + + @Test(groups = { "wso2.am" }, description = "Test get and update shared scope", + dependsOnMethods = "testAddSharedScope") + public void testGetAndUpdateSharedScope() throws Exception { + ScopeDTO sharedScopeDTO = restAPIPublisher.getSharedScopeById(sharedScopeId); + Assert.assertEquals(sharedScopeDTO.getName(), sharedScopeName, + "Shared scope name does not match with the expected name"); + Assert.assertEquals(sharedScopeDTO.getDisplayName(), sharedScopeDisplayName, + "Shared scope display name does not match with the expected display name"); + Assert.assertTrue(sharedScopeDTO.getBindings().contains("admin"), + "Shared scope does not include the expected role"); + + sharedScopeDTO.setDescription(updatedDescription); + ScopeDTO updateScopeDTO = restAPIPublisher.updateSharedScope(sharedScopeId, sharedScopeDTO); + Assert.assertEquals(updateScopeDTO.getDescription(), updatedDescription, + "Shared scope description does not match with the expected description"); + + sharedScopeDTO.setDescription(updatedDescription1); + updateScopeDTO = restAPIPublisher.updateSharedScope(sharedScopeId, sharedScopeDTO); + Assert.assertEquals(updateScopeDTO.getDescription(), updatedDescription1, + "Shared scope description does not match with the expected description"); + + sharedScopeDTO.setDescription(updatedDescription2); + updateScopeDTO = restAPIPublisher.updateSharedScope(sharedScopeId, sharedScopeDTO); + Assert.assertEquals(updateScopeDTO.getDescription(), updatedDescription2, + "Shared scope description does not match with the expected description"); + } + + @Test(groups = { "wso2.am" }, description = "Test delete shared scope", + dependsOnMethods = "testGetAndUpdateSharedScope") + public void testDeleteSharedScope() throws Exception { + restAPIPublisher.deleteSharedScope(sharedScopeId); + } + + @AfterClass(alwaysRun = true) + public void destroy() throws Exception { + super.cleanUp(); + serverConfigurationManager.restoreToLastConfiguration(); + } +} diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/TenantDomainValidationTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/TenantDomainValidationTestCase.java index a4d2ae0b3d..2dd6181cc4 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/TenantDomainValidationTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/TenantDomainValidationTestCase.java @@ -20,19 +20,16 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import org.wso2.am.integration.clients.publisher.api.v1.dto.APIOperationsDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyGenerateRequestDTO; import org.wso2.am.integration.test.impl.RestAPIPublisherImpl; import org.wso2.am.integration.test.impl.RestAPIStoreImpl; -import org.wso2.am.integration.test.utils.base.APIMIntegrationBaseTest; import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants; -import org.wso2.am.integration.test.utils.bean.APILifeCycleAction; import org.wso2.am.integration.test.utils.bean.APIRequest; +import org.wso2.am.integration.tests.api.lifecycle.APIManagerLifecycleBaseTest; import org.wso2.carbon.automation.test.utils.http.client.HttpRequestUtil; import org.wso2.carbon.automation.test.utils.http.client.HttpResponse; -import org.wso2.carbon.tenant.mgt.stub.TenantMgtAdminServiceExceptionException; import java.net.URL; import java.util.ArrayList; @@ -41,8 +38,9 @@ import java.util.Map; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; -public class TenantDomainValidationTestCase extends APIMIntegrationBaseTest { +public class TenantDomainValidationTestCase extends APIManagerLifecycleBaseTest { private final String TENANT_DOMAIN = "abc.com"; private final String TENANT_ADMIN_USERNAME = "admin"; @@ -73,15 +71,14 @@ public void testAdditionOfTenantWithInvalidDomain() throws Exception { try { tenantManagementServiceClient.addTenant(INVALID_TENANT_DOMAIN, TENANT_ADMIN_PASSWORD, TENANT_ADMIN_USERNAME, "demo"); - } catch (TenantMgtAdminServiceExceptionException e) { - assertEquals(e.getFaultMessage().getTenantMgtAdminServiceException().getMessage(), - "The tenant domain ' " + INVALID_TENANT_DOMAIN + " ' contains one or more illegal " + - "characters. The valid characters are lowercase letters, numbers, '.', '-' and '_'."); + } catch (Exception e) { + assertTrue(e.getMessage().contains("The tenant domain " + INVALID_TENANT_DOMAIN + " contains one or more illegal " + + "characters. The valid characters are lowercase letters, numbers, '.', '-' and '_'.")); } } @Test(groups = { - "wso2.am"}, description = "Testing API invocation with a different tenant domain") + "wso2.am"}, description = "Testing API invocation with a different tenant domain", dependsOnMethods = "testAdditionOfTenantWithInvalidDomain") public void testAPIInvokeWithTenants() throws Exception { // Add a new tenant @@ -93,40 +90,29 @@ public void testAPIInvokeWithTenants() throws Exception { restAPIStore = new RestAPIStoreImpl(TENANT_ADMIN_USERNAME, TENANT_ADMIN_PASSWORD, TENANT_DOMAIN, storeURLHttps); - Thread.sleep(15000); - - APIRequest apiCreationRequestBean; - apiCreationRequestBean = new APIRequest(API_NAME, API_CONTEXT, new URL(apiProductionEndPointUrl)); - apiCreationRequestBean.setVersion(API_VERSION); - apiCreationRequestBean.setDescription(API_DESC); - apiCreationRequestBean.setProvider(TENANT_ADMIN_USER); - apiCreationRequestBean.setTier(APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED); - APIOperationsDTO apiOperationsDTO = new APIOperationsDTO(); - apiOperationsDTO.setVerb("GET"); - apiOperationsDTO.setTarget("/customers/{id}"); - List operationsDTOS = new ArrayList<>(); - operationsDTOS.add(apiOperationsDTO); - apiCreationRequestBean.setOperationsDTOS(operationsDTOS); - apiCreationRequestBean.setOperationsDTOS(operationsDTOS); - - HttpResponse apiCreationResponse = restAPIPublisher.addAPI(apiCreationRequestBean); - apiID = apiCreationResponse.getData(); - - restAPIPublisher - .changeAPILifeCycleStatus(apiID, APILifeCycleAction.PUBLISH.getAction(), null); - - HttpResponse applicationResponse = restAPIStore - .createApplication(APP_NAME, "Application to test Schema " - + "Validation", APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED, - ApplicationDTO.TokenTypeEnum.JWT); - ArrayList grantTypes = new ArrayList<>(); - grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD); - grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL); + //Create the Application and the API + HttpResponse applicationResponse = restAPIStore.createApplication(APP_NAME, + "Test Application RevokeOneTimeToken", APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED, + ApplicationDTO.TokenTypeEnum.JWT); appID = applicationResponse.getData(); - restAPIStore.subscribeToAPI(apiID, appID, "Gold"); - ApplicationKeyDTO applicationKeyDTO = restAPIStore.generateKeys(appID, "36000", "", - ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes); + APIRequest apiRequest = new APIRequest(API_NAME, API_CONTEXT, new URL(apiProductionEndPointUrl)); + apiRequest.setVersion(API_VERSION); + apiRequest.setTiersCollection(APIMIntegrationConstants.API_TIER.UNLIMITED); + apiRequest.setTier(APIMIntegrationConstants.API_TIER.UNLIMITED); + apiID = createPublishAndSubscribeToAPIUsingRest(apiRequest, restAPIPublisher, restAPIStore, appID, + APIMIntegrationConstants.API_TIER.UNLIMITED); + + //Create the JWT access token + List grantTypes = new ArrayList<>(); + grantTypes.add("client_credentials"); + ArrayList scopes = new ArrayList<>(); + scopes.add("OTT"); + + ApplicationKeyDTO applicationKeyDTO = restAPIStore + .generateKeys(appID, "3600", null, + ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, scopes, grantTypes); + assert applicationKeyDTO.getToken() != null; String accessToken = applicationKeyDTO.getToken().getAccessToken(); // Invoke the API with a valid tenant domain @@ -144,7 +130,7 @@ public void testAPIInvokeWithTenants() throws Exception { "Expected response code 500 but received " + response.getResponseCode() + " when invoking API with " + "invalid tenant domain"); - // Invoke the API with a valid tenant domain again to check nothing have breaked + // Invoke the API with a valid tenant domain again to check nothing have broken gatewayUrl = gatewayUrlsWrk.getWebAppURLNhttp() + "t/" + TENANT_DOMAIN + "/"; response = invokeAPI(accessToken, gatewayUrl); @@ -168,9 +154,12 @@ private HttpResponse invokeAPI(String accessToken, String gatewayUrl) @AfterClass(alwaysRun = true) public void destroy() throws Exception { - restAPIStore.deleteApplication(appID); - restAPIPublisher.deleteAPI(apiID); + if (appID != null) { + restAPIStore.deleteApplication(appID); + } + if (apiID != null) { + restAPIPublisher.deleteAPI(apiID); + } tenantManagementServiceClient.deleteTenant(TENANT_DOMAIN); - super.cleanUp(); } } diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/configFiles/webSocketWithTracing/deployment.toml b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/configFiles/webSocketWithTracing/deployment.toml index 2526f60b3b..e6e8d824a5 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/configFiles/webSocketWithTracing/deployment.toml +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/configFiles/webSocketWithTracing/deployment.toml @@ -45,7 +45,9 @@ show_as_token_endpoint_url = true service_url = "https://localhost:${mgt.transport.https.port}/services/" username = "admin" password = "admin" -http_endpoint = "ws://wsserverhost:9797" +ws_endpoint = "ws://localhost:9960/" +wss_endpoint = "wss://localhost:9960/" +http_endpoint = "http://wsserverhost:9797" https_endpoint = "https://serverhost:9898" [[apim.gateway.environment]] diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties index f06c2dbcdb..e1e1d0fae5 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties @@ -185,7 +185,7 @@ appender.osgi.type = PaxOsgi appender.osgi.name = PaxOsgi appender.osgi.filter = * -loggers = AUDIT_LOG, trace-messages, org-apache-coyote, com-hazelcast, Owasp-CsrfGuard, org-apache-axis2-wsdl-codegen-writer-PrettyPrinter, org-apache-axis2-clustering, org-apache-catalina, org-apache-tomcat, org-wso2-carbon-apacheds, org-apache-directory-server-ldap, org-apache-directory-server-core-event, com-atomikos, org-quartz, org-apache-jackrabbit-webdav, org-apache-juddi, org-apache-commons-digester-Digester, org-apache-jasper-compiler-TldLocationsCache, org-apache-qpid, org-apache-qpid-server-Main, qpid-message, qpid-message-broker-listening, org-apache-tiles, org-apache-commons-httpclient, org-apache-solr, me-prettyprint-cassandra-hector-TimingLogger, org-apache-axis-enterprise, org-apache-directory-shared-ldap, org-apache-directory-server-ldap-handlers, org-apache-directory-shared-ldap-entry-DefaultServerAttribute, org-apache-directory-server-core-DefaultDirectoryService, org-apache-directory-shared-ldap-ldif-LdifReader, org-apache-directory-server-ldap-LdapProtocolHandler, org-apache-directory-server-core, org-apache-directory-server-ldap-LdapSession, DataNucleus, Datastore, Datastore-Schema, JPOX-Datastore, JPOX-Plugin, JPOX-MetaData, JPOX-Query, JPOX-General, JPOX-Enhancer, org-apache-hadoop-hive, hive, ExecMapper, ExecReducer, net-sf-ehcache-config-ConfigurationFactory, axis2Deployment, equinox, tomcat2, StAXDialectDetector, trace, synapse, synapse_transport, axis2, axis2_transport, org-wso2-carbon, hunsicker, thrift-publisher, service_logger, trace_logger, org-wso2-carbon-apimgt-gateway-mediators-BotDetectionMediator, wso2-callhome, correlation, JAGGERY_LOG, API_LOG +loggers = AUDIT_LOG, trace-messages, org-apache-coyote, com-hazelcast, Owasp-CsrfGuard, org-apache-axis2-wsdl-codegen-writer-PrettyPrinter, org-apache-axis2-clustering, org-apache-catalina, org-apache-tomcat, org-wso2-carbon-apacheds, org-apache-directory-server-ldap, org-apache-directory-server-core-event, com-atomikos, org-quartz, org-apache-jackrabbit-webdav, org-apache-juddi, org-apache-commons-digester-Digester, org-apache-jasper-compiler-TldLocationsCache, org-apache-qpid, org-apache-qpid-server-Main, qpid-message, qpid-message-broker-listening, org-apache-tiles, org-apache-commons-httpclient, org-apache-solr, me-prettyprint-cassandra-hector-TimingLogger, org-apache-axis-enterprise, org-apache-directory-shared-ldap, org-apache-directory-server-ldap-handlers, org-apache-directory-shared-ldap-entry-DefaultServerAttribute, org-apache-directory-server-core-DefaultDirectoryService, org-apache-directory-shared-ldap-ldif-LdifReader, org-apache-directory-server-ldap-LdapProtocolHandler, org-apache-directory-server-core, org-apache-directory-server-ldap-LdapSession, DataNucleus, Datastore, Datastore-Schema, JPOX-Datastore, JPOX-Plugin, JPOX-MetaData, JPOX-Query, JPOX-General, JPOX-Enhancer, org-apache-hadoop-hive, hive, ExecMapper, ExecReducer, net-sf-ehcache-config-ConfigurationFactory, axis2Deployment, equinox, tomcat2, StAXDialectDetector, trace, synapse, synapse_transport, axis2, axis2_transport, org-wso2-carbon, hunsicker, thrift-publisher, service_logger, trace_logger, org-wso2-carbon-apimgt-gateway-mediators-BotDetectionMediator, wso2-callhome, correlation, JAGGERY_LOG, API_LOG, synapse-wire logger.API_LOG.name = API_LOG logger.API_LOG.level = INFO diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/scopes/deployment.toml b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/scopes/deployment.toml new file mode 100644 index 0000000000..fdbecb68de --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/scopes/deployment.toml @@ -0,0 +1,116 @@ +[server] +hostname = "localhost" +#offset=0 +base_path = "${carbon.protocol}://${carbon.host}:${carbon.management.port}" +server_role = "default" +enable_shutdown_from_api = true +enable_restart_from_api = true + +[super_admin] +username = "admin" +password = "admin" +create_admin_account = true + +[user_store] +type = "database_unique_id" + +[database.apim_db] +driver = "$env{API_MANAGER_DATABASE_DRIVER}" +url = "$env{API_MANAGER_DATABASE_URL}" +username = "$env{API_MANAGER_DATABASE_USERNAME}" +password = "$env{API_MANAGER_DATABASE_PASSWORD}" +validationQuery = "$env{API_MANAGER_DATABASE_VALIDATION_QUERY}" + +[database.shared_db] +driver = "$env{SHARED_DATABASE_DRIVER}" +url = "$env{SHARED_DATABASE_URL}" +username = "$env{SHARED_DATABASE_USERNAME}" +password = "$env{SHARED_DATABASE_PASSWORD}" +validationQuery = "$env{SHARED_DATABASE_VALIDATION_QUERY}" + +[keystore.tls] +file_name = "wso2carbon.jks" +type = "JKS" +password = "wso2carbon" +alias = "wso2carbon" +key_password = "wso2carbon" + +[[apim.gateway.environment]] +name = "Default" +type = "hybrid" +provider = "wso2" +display_in_api_console = true +description = "This is a hybrid gateway that handles both production and sandbox token traffic." +show_as_token_endpoint_url = true +service_url = "https://localhost:${mgt.transport.https.port}/services/" +username = "admin" +password = "admin" +ws_endpoint = "ws://localhost:9099" +http_endpoint = "http://localhost:${http.nio.port}" +https_endpoint = "https://localhost:${https.nio.port}" + +[[apim.gateway.environment]] +name = "devportalEnv" +display_name = "Developer portal Test Environment" +type = "hybrid" +display_in_api_console = false +description = "development api gateway broker" +provider = "solace" +service_url = "http://localhost:9960" +username = "testUser" +ws_endpoint = "ws://localhost:9960/" +wss_endpoint = "wss://localhost:9960/" +http_endpoint = "http://localhost:9960" +https_endpoint = "https://localhost:9960/" +password = "testPassword" +show_as_token_endpoint_url = false + +[apim.gateway.environment.properties] +Organization = "TestWSO2" +DisplayName = "Developer portal Test Environment" +DevAccountName = "devPortTestEnv" + +[apim.cors] +allow_origins = "*" +allow_methods = ["GET","PUT","POST","DELETE","PATCH","OPTIONS"] +allow_headers = ["authorization","Access-Control-Allow-Origin","Content-Type","SOAPAction"] +allow_credentials = false + +[[event_handler]] +name="userPostSelfRegistration" +subscriptions=["POST_ADD_USER"] + +[transport] +passthru_https.listener.ssl_profile_interval = 6000 +passthru_https.sender.ssl_profile.interval = 6000 + +[security_audit] +api_token="b57973cf-b74c-4ade-921d-ece83251eceb" +collection_id="f73b8171-4f71-499b-891a-d34aa71f2d45" +base_url="https://localhost:9943/am-auditApi-sample/api/auditapi" +global=true + +[apim.certificate_reloader] +period = "1m" + +[database.local] +url = "jdbc:h2:./repository/database/WSO2CARBON_DB;DB_CLOSE_ON_EXIT=FALSE" + +[[event_listener]] +id = "token_revocation" +type = "org.wso2.carbon.identity.core.handler.AbstractIdentityHandler" +name = "org.wso2.is.notification.ApimOauthEventInterceptor" +order = 1 +[event_listener.properties] +notification_endpoint = "https://localhost:${mgt.transport.https.port}/internal/data/v1/notify" +username = "${admin.username}" +password = "${admin.password}" +'header.X-WSO2-KEY-MANAGER' = "default" + +[apim.sync_runtime_artifacts.gateway.skip_list] +apis = ["admin--git2231head_v1.0.0.xml","admin--PizzaShackAPI_v1.0.0.xml","admin--ScriptMediatorAPI_v1.0.xml", + "APIThrottleBackendAPI.xml","BackEndSecurity.xml","DigestAuth_API.xml","git2231.xml","HttpPATCHSupport_API.xml","JWKS-Backend.xml","JWTBackendAPI.xml","multiVSR_v1.0.0.xml","Response_API_1.xml","Response_API_2.xml","Response_Custom_API.xml","Response_Error_API.xml","Response_Loc_API.xml","SpecialCRN_v1.0.0.xml","status_code_204_API.xml","stockquote.xml","XML_API.xml","Version1.xml","Version2.xml","schemaValidationAPI.xml"] + +[apim.http_client] +max_total= "200" +default_max_per_route= "2" diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/toml_config/case1/deployment.toml b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/toml_config/case1/deployment.toml index 2d565bd899..b920268972 100755 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/toml_config/case1/deployment.toml +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/toml_config/case1/deployment.toml @@ -171,8 +171,6 @@ allow_origins = ["origin1","origin2"] allow_methods = ["GET","PUT","POST","DELETE","PATCH","OPTIONS"] allow_headers = ["authorization","Access-Control-Allow-Origin","Content-Type","SOAPAction","X-custom"] allow_credentials = true - - # [apim.throttling] enable_advanced_throttling = "true" diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v2/oas_publisher.json b/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v2/oas_publisher.json index 61216a59a7..1969fcfa1c 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v2/oas_publisher.json +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v2/oas_publisher.json @@ -71,6 +71,7 @@ } } }, + "x-wso2-api-key-header": "ApiKey", "securityDefinitions" : { "default" : { "type" : "oauth2", diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/oas_publisher.json b/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/oas_publisher.json index 4c41d21f1e..804582e773 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/oas_publisher.json +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/oas_publisher.json @@ -94,6 +94,7 @@ } } }, + "x-wso2-api-key-header": "ApiKey", "x-throttling-tier" : "Unlimited", "x-wso2-cors" : { "corsConfigurationEnabled" : true, diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml index 8c5912b526..8ed23657b8 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml @@ -198,6 +198,13 @@ + + + + + + + @@ -422,6 +429,7 @@ + diff --git a/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-superTenant.json b/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-superTenant.json index 71d87156de..1888d155e4 100755 --- a/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-superTenant.json +++ b/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-superTenant.json @@ -4,12 +4,12 @@ "API_PUBLISH" : "839", "RETRIEVE_ALL_PUBLISHER" : "77", "RETRIEVE_ALL_STORE" : "300", - "RETRIEVE_API_PUBLISHER" : "75", + "RETRIEVE_API_PUBLISHER" : "77", "RETRIEVE_API_STORE" : "42", "CREATE_APPLICATION" : "260", "SUBSCRIBE_TO_API" : "74", "GENERATE_JWT_TOKEN" : "17", "INVOKE_API" :"0", - "CREATE_REVISION_AND_DEPLOY" :"366" + "CREATE_REVISION_AND_DEPLOY" :"375" } ] \ No newline at end of file diff --git a/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-tenant.json b/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-tenant.json index 9d6cfa9978..8be24b6fba 100755 --- a/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-tenant.json +++ b/modules/integration/tests-integration/tests-benchmark/src/test/resources/benchmark-values/benchmark-values-jdbc-tenant.json @@ -4,12 +4,12 @@ "API_PUBLISH" : "851", "RETRIEVE_ALL_PUBLISHER" : "82", "RETRIEVE_ALL_STORE" : "316", - "RETRIEVE_API_PUBLISHER" : "75", + "RETRIEVE_API_PUBLISHER" : "77", "RETRIEVE_API_STORE" : "42", "CREATE_APPLICATION" : "390", "SUBSCRIBE_TO_API" : "74", "GENERATE_JWT_TOKEN" : "17", "INVOKE_API" :"0", - "CREATE_REVISION_AND_DEPLOY" :"388" + "CREATE_REVISION_AND_DEPLOY" :"397" } ] \ No newline at end of file diff --git a/modules/integration/tests-integration/tests-restart/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties b/modules/integration/tests-integration/tests-restart/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties index f06c2dbcdb..e1e1d0fae5 100644 --- a/modules/integration/tests-integration/tests-restart/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties +++ b/modules/integration/tests-integration/tests-restart/src/test/resources/artifacts/AM/lifecycletest/log4j2.properties @@ -185,7 +185,7 @@ appender.osgi.type = PaxOsgi appender.osgi.name = PaxOsgi appender.osgi.filter = * -loggers = AUDIT_LOG, trace-messages, org-apache-coyote, com-hazelcast, Owasp-CsrfGuard, org-apache-axis2-wsdl-codegen-writer-PrettyPrinter, org-apache-axis2-clustering, org-apache-catalina, org-apache-tomcat, org-wso2-carbon-apacheds, org-apache-directory-server-ldap, org-apache-directory-server-core-event, com-atomikos, org-quartz, org-apache-jackrabbit-webdav, org-apache-juddi, org-apache-commons-digester-Digester, org-apache-jasper-compiler-TldLocationsCache, org-apache-qpid, org-apache-qpid-server-Main, qpid-message, qpid-message-broker-listening, org-apache-tiles, org-apache-commons-httpclient, org-apache-solr, me-prettyprint-cassandra-hector-TimingLogger, org-apache-axis-enterprise, org-apache-directory-shared-ldap, org-apache-directory-server-ldap-handlers, org-apache-directory-shared-ldap-entry-DefaultServerAttribute, org-apache-directory-server-core-DefaultDirectoryService, org-apache-directory-shared-ldap-ldif-LdifReader, org-apache-directory-server-ldap-LdapProtocolHandler, org-apache-directory-server-core, org-apache-directory-server-ldap-LdapSession, DataNucleus, Datastore, Datastore-Schema, JPOX-Datastore, JPOX-Plugin, JPOX-MetaData, JPOX-Query, JPOX-General, JPOX-Enhancer, org-apache-hadoop-hive, hive, ExecMapper, ExecReducer, net-sf-ehcache-config-ConfigurationFactory, axis2Deployment, equinox, tomcat2, StAXDialectDetector, trace, synapse, synapse_transport, axis2, axis2_transport, org-wso2-carbon, hunsicker, thrift-publisher, service_logger, trace_logger, org-wso2-carbon-apimgt-gateway-mediators-BotDetectionMediator, wso2-callhome, correlation, JAGGERY_LOG, API_LOG +loggers = AUDIT_LOG, trace-messages, org-apache-coyote, com-hazelcast, Owasp-CsrfGuard, org-apache-axis2-wsdl-codegen-writer-PrettyPrinter, org-apache-axis2-clustering, org-apache-catalina, org-apache-tomcat, org-wso2-carbon-apacheds, org-apache-directory-server-ldap, org-apache-directory-server-core-event, com-atomikos, org-quartz, org-apache-jackrabbit-webdav, org-apache-juddi, org-apache-commons-digester-Digester, org-apache-jasper-compiler-TldLocationsCache, org-apache-qpid, org-apache-qpid-server-Main, qpid-message, qpid-message-broker-listening, org-apache-tiles, org-apache-commons-httpclient, org-apache-solr, me-prettyprint-cassandra-hector-TimingLogger, org-apache-axis-enterprise, org-apache-directory-shared-ldap, org-apache-directory-server-ldap-handlers, org-apache-directory-shared-ldap-entry-DefaultServerAttribute, org-apache-directory-server-core-DefaultDirectoryService, org-apache-directory-shared-ldap-ldif-LdifReader, org-apache-directory-server-ldap-LdapProtocolHandler, org-apache-directory-server-core, org-apache-directory-server-ldap-LdapSession, DataNucleus, Datastore, Datastore-Schema, JPOX-Datastore, JPOX-Plugin, JPOX-MetaData, JPOX-Query, JPOX-General, JPOX-Enhancer, org-apache-hadoop-hive, hive, ExecMapper, ExecReducer, net-sf-ehcache-config-ConfigurationFactory, axis2Deployment, equinox, tomcat2, StAXDialectDetector, trace, synapse, synapse_transport, axis2, axis2_transport, org-wso2-carbon, hunsicker, thrift-publisher, service_logger, trace_logger, org-wso2-carbon-apimgt-gateway-mediators-BotDetectionMediator, wso2-callhome, correlation, JAGGERY_LOG, API_LOG, synapse-wire logger.API_LOG.name = API_LOG logger.API_LOG.level = INFO diff --git a/pom.xml b/pom.xml index a20359ec10..aab2520e11 100644 --- a/pom.xml +++ b/pom.xml @@ -1277,10 +1277,10 @@ 5.3.5 - 9.0.432 + 9.0.453 - 9.28.153 + 9.28.179 [9.0.0, 10.0.0) @@ -1347,7 +1347,7 @@ 1.8 3.0-FINAL 1.0.0.M8-wso2v1 - 4.0.0-wso2v20 + 4.0.0-wso2v50 1.0.2 1.6.1-wso2v85 1.2.11-wso2v25