diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 73dc75db4f2..5c37ef659a8 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -2,7 +2,7 @@
name: ❗️ Issue/Bug report
about: Report issue or bug related to the project
title: ''
-labels: 'bug'
+labels: 'Type/Bug'
assignees: ''
---
diff --git a/.github/ISSUE_TEMPLATE/doc_issues.md b/.github/ISSUE_TEMPLATE/doc_issues.md
index d20a232cf74..76753cbc4f3 100644
--- a/.github/ISSUE_TEMPLATE/doc_issues.md
+++ b/.github/ISSUE_TEMPLATE/doc_issues.md
@@ -2,7 +2,7 @@
name: 📕 Doc issues
about: Please report documentation issues here
title: ''
-labels: 'docs'
+labels: 'Type/Docs'
assignees: ''
---
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index a2679026f0a..57bdb424dbf 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -2,7 +2,7 @@
name: ➕ Feature request
about: Suggest an idea for this project
title: ''
-labels: 'feature'
+labels: 'Type/NewFeature'
assignees: ''
---
diff --git a/.github/ISSUE_TEMPLATE/improvement.md b/.github/ISSUE_TEMPLATE/improvement.md
index fa3be360593..31f29c5a91a 100644
--- a/.github/ISSUE_TEMPLATE/improvement.md
+++ b/.github/ISSUE_TEMPLATE/improvement.md
@@ -2,7 +2,7 @@
name: ✅ Improvement suggestion
about: Suggest an improvement for the project
title: ''
-labels: 'improvement'
+labels: 'Type/Improvement'
assignees: ''
---
diff --git a/.github/ISSUE_TEMPLATE/test_request.md b/.github/ISSUE_TEMPLATE/test_request.md
index 896d1e0e2a3..3b8c0e53d73 100644
--- a/.github/ISSUE_TEMPLATE/test_request.md
+++ b/.github/ISSUE_TEMPLATE/test_request.md
@@ -2,7 +2,7 @@
name: "✅ Testing Task"
about: Create a testing task to improve the quality of the product.
title: ''
-labels: 'test'
+labels: 'Type/Test'
assignees: ''
---
diff --git a/.github/workflows/product-is-builder-jdk17.yml b/.github/workflows/product-is-builder-jdk17.yml
index 3d0c722a641..c94a139c99d 100644
--- a/.github/workflows/product-is-builder-jdk17.yml
+++ b/.github/workflows/product-is-builder-jdk17.yml
@@ -3,8 +3,8 @@ name: product-is-builder-jdk17
on:
workflow_dispatch:
schedule:
-# At 00:00 on day-of-month 1
- - cron: '0 0 1 * *'
+# Daily at 17:00 UTC (10.30 PM SL time)
+ - cron: '0 17 * * *'
env:
@@ -39,8 +39,10 @@ jobs:
ls
cd modules/integration/
mvn clean install --batch-mode | tee mvn-build.log
+
PR_BUILD_STATUS=$(cat mvn-build.log | grep "\[INFO\] BUILD" | grep -oE '[^ ]+$')
PR_TEST_RESULT=$(sed -n -e '/\[INFO\] Results:/,/\[INFO\] Tests run:/ p' mvn-build.log)
+
PR_BUILD_FINAL_RESULT=$(
echo "==========================================================="
echo "product-is BUILD $PR_BUILD_STATUS"
@@ -48,12 +50,21 @@ jobs:
echo ""
echo "$PR_TEST_RESULT"
)
+
PR_BUILD_RESULT_LOG_TEMP=$(echo "$PR_BUILD_FINAL_RESULT" | sed 's/$/%0A/')
PR_BUILD_RESULT_LOG=$(echo $PR_BUILD_RESULT_LOG_TEMP)
echo "::warning::$PR_BUILD_RESULT_LOG"
+
PR_BUILD_SUCCESS_COUNT=$(grep -o -i "\[INFO\] BUILD SUCCESS" mvn-build.log | wc -l)
- if [ "$PR_BUILD_SUCCESS_COUNT" != "3" ]; then
+ if [ "$PR_BUILD_SUCCESS_COUNT" != "11" ]; then
+ echo "Success Count $PR_BUILD_SUCCESS_COUNT"
echo "PR BUILD not successfull. Aborting."
echo "::error::PR BUILD not successfull. Check artifacts for logs."
exit 1
fi
+
+ echo ""
+ echo "=========================================================="
+ echo "Build completed"
+ echo "=========================================================="
+ echo ""
diff --git a/.github/workflows/product-is-builder-jdk21.yml b/.github/workflows/product-is-builder-jdk21.yml
new file mode 100644
index 00000000000..632f0b71100
--- /dev/null
+++ b/.github/workflows/product-is-builder-jdk21.yml
@@ -0,0 +1,70 @@
+name: product-is-builder-jdk21
+
+on:
+ workflow_dispatch:
+ schedule:
+# Daily at 23:00 UTC (04.30 AM SL time)
+ - cron: '0 23 * * *'
+
+
+env:
+ MAVEN_OPTS: -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.http.retryHandler.class=standard -Dmaven.wagon.http.retryHandler.count=3
+
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ env:
+ JAVA_TOOL_OPTIONS: "-Djdk.util.zip.disableZip64ExtraFieldValidation=true -Djdk.nio.zipfs.allowDotZipEntry=true"
+
+ steps:
+ - name: Checkout repository code
+ uses: actions/checkout@v2
+ - name: Set up Adopt JDK 11
+ uses: actions/setup-java@v2
+ with:
+ java-version: "11"
+ distribution: "adopt"
+ - name: Product-IS build with JDK 11 without Integration Tests
+ run: |
+ mvn clean install --batch-mode -Dmaven.test.skip=true | tee mvn-build.log
+ - name: Set up Adopt JDK 21
+ uses: actions/setup-java@v2
+ with:
+ java-version: "21"
+ distribution: "adopt"
+ - name: Product-IS build with JDK 21 with Integration Tests
+ run: |
+ ls
+ cd modules/integration/
+ mvn clean install --batch-mode | tee mvn-build.log
+
+ PR_BUILD_STATUS=$(cat mvn-build.log | grep "\[INFO\] BUILD" | grep -oE '[^ ]+$')
+ PR_TEST_RESULT=$(sed -n -e '/\[INFO\] Results:/,/\[INFO\] Tests run:/ p' mvn-build.log)
+
+ PR_BUILD_FINAL_RESULT=$(
+ echo "==========================================================="
+ echo "product-is BUILD $PR_BUILD_STATUS"
+ echo "=========================================================="
+ echo ""
+ echo "$PR_TEST_RESULT"
+ )
+
+ PR_BUILD_RESULT_LOG_TEMP=$(echo "$PR_BUILD_FINAL_RESULT" | sed 's/$/%0A/')
+ PR_BUILD_RESULT_LOG=$(echo $PR_BUILD_RESULT_LOG_TEMP)
+ echo "::warning::$PR_BUILD_RESULT_LOG"
+
+ PR_BUILD_SUCCESS_COUNT=$(grep -o -i "\[INFO\] BUILD SUCCESS" mvn-build.log | wc -l)
+ if [ "$PR_BUILD_SUCCESS_COUNT" != "11" ]; then
+ echo "Success Count $PR_BUILD_SUCCESS_COUNT"
+ echo "PR BUILD not successfull. Aborting."
+ echo "::error::PR BUILD not successfull. Check artifacts for logs."
+ exit 1
+ fi
+
+ echo ""
+ echo "=========================================================="
+ echo "Build completed"
+ echo "=========================================================="
+ echo ""
diff --git a/modules/api-resources/api-resources-full/pom.xml b/modules/api-resources/api-resources-full/pom.xml
index 6db52472deb..00458995709 100644
--- a/modules/api-resources/api-resources-full/pom.xml
+++ b/modules/api-resources/api-resources-full/pom.xml
@@ -23,12 +23,12 @@
org.wso2.is
api-resources
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
api-resources-full
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
war
WSO2 Identity Server - All Rest API
diff --git a/modules/api-resources/pom.xml b/modules/api-resources/pom.xml
index 55e35f96cbc..e8d6c5950b3 100644
--- a/modules/api-resources/pom.xml
+++ b/modules/api-resources/pom.xml
@@ -23,12 +23,12 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
api-resources
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
pom
WSO2 Identity Server - Rest API
diff --git a/modules/authenticators/pom.xml b/modules/authenticators/pom.xml
index f9f8a4a988a..a62e8cd241f 100644
--- a/modules/authenticators/pom.xml
+++ b/modules/authenticators/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/modules/connectors/pom.xml b/modules/connectors/pom.xml
index 95a838e3656..ecf453da1e9 100644
--- a/modules/connectors/pom.xml
+++ b/modules/connectors/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/modules/distribution/pom.xml b/modules/distribution/pom.xml
index d0a9d350ec0..10f231e8f86 100755
--- a/modules/distribution/pom.xml
+++ b/modules/distribution/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/features/org.wso2.identity.styles.feature/pom.xml b/modules/features/org.wso2.identity.styles.feature/pom.xml
index dbb2eb7e0c4..effcc8fc8bf 100644
--- a/modules/features/org.wso2.identity.styles.feature/pom.xml
+++ b/modules/features/org.wso2.identity.styles.feature/pom.xml
@@ -20,7 +20,7 @@
org.wso2.is
identity-features
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/features/org.wso2.identity.ui.feature/pom.xml b/modules/features/org.wso2.identity.ui.feature/pom.xml
index 5634b9f61b4..ab4a8bf4c95 100644
--- a/modules/features/org.wso2.identity.ui.feature/pom.xml
+++ b/modules/features/org.wso2.identity.ui.feature/pom.xml
@@ -20,7 +20,7 @@
org.wso2.is
identity-features
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/features/org.wso2.identity.utils.feature/pom.xml b/modules/features/org.wso2.identity.utils.feature/pom.xml
index 1ab4b0eced1..78bb94dee1c 100644
--- a/modules/features/org.wso2.identity.utils.feature/pom.xml
+++ b/modules/features/org.wso2.identity.utils.feature/pom.xml
@@ -20,7 +20,7 @@
org.wso2.is
identity-features
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/features/pom.xml b/modules/features/pom.xml
index 138eb89e021..84eae0f1027 100644
--- a/modules/features/pom.xml
+++ b/modules/features/pom.xml
@@ -17,7 +17,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration-ui-templates/pom.xml b/modules/integration-ui-templates/pom.xml
index fc15bcbac78..c06645ec101 100644
--- a/modules/integration-ui-templates/pom.xml
+++ b/modules/integration-ui-templates/pom.xml
@@ -22,7 +22,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/pom.xml b/modules/integration/pom.xml
index f086e42834c..a37194ceee4 100644
--- a/modules/integration/pom.xml
+++ b/modules/integration/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/tests-common/admin-clients/pom.xml b/modules/integration/tests-common/admin-clients/pom.xml
index 58c4a93f285..890ad2e95c4 100644
--- a/modules/integration/tests-common/admin-clients/pom.xml
+++ b/modules/integration/tests-common/admin-clients/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/tests-common/extensions/pom.xml b/modules/integration/tests-common/extensions/pom.xml
index d3c6b8688c2..3925de11624 100644
--- a/modules/integration/tests-common/extensions/pom.xml
+++ b/modules/integration/tests-common/extensions/pom.xml
@@ -22,7 +22,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/tests-common/integration-test-utils/pom.xml b/modules/integration/tests-common/integration-test-utils/pom.xml
index 748d9a90c3f..f307eb70e99 100644
--- a/modules/integration/tests-common/integration-test-utils/pom.xml
+++ b/modules/integration/tests-common/integration-test-utils/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/tests-common/jacoco-report-generator/pom.xml b/modules/integration/tests-common/jacoco-report-generator/pom.xml
index b562b93be9a..93f365fdfa2 100644
--- a/modules/integration/tests-common/jacoco-report-generator/pom.xml
+++ b/modules/integration/tests-common/jacoco-report-generator/pom.xml
@@ -22,7 +22,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/tests-common/pom.xml b/modules/integration/tests-common/pom.xml
index b5b09423f58..efb4802f2b9 100644
--- a/modules/integration/tests-common/pom.xml
+++ b/modules/integration/tests-common/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/integration/tests-common/ui-pages/pom.xml b/modules/integration/tests-common/ui-pages/pom.xml
index 2671a4382e9..dff6e7703cd 100644
--- a/modules/integration/tests-common/ui-pages/pom.xml
+++ b/modules/integration/tests-common/ui-pages/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/integration/tests-integration/pom.xml b/modules/integration/tests-integration/pom.xml
index 98510b0f1b1..6eb24e057ca 100644
--- a/modules/integration/tests-integration/pom.xml
+++ b/modules/integration/tests-integration/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/integration/tests-integration/tests-backend/pom.xml b/modules/integration/tests-integration/tests-backend/pom.xml
index ad39b54dcb5..ef9e6f50d8a 100644
--- a/modules/integration/tests-integration/tests-backend/pom.xml
+++ b/modules/integration/tests-integration/tests-backend/pom.xml
@@ -18,7 +18,7 @@
org.wso2.is
identity-integration-tests
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
@@ -1098,5 +1098,10 @@
jsoup
test
+
+ com.nimbusds
+ nimbus-jose-jwt
+ test
+
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/applicationNativeAuthentication/ApplicationNativeAuthentication2FATestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/applicationNativeAuthentication/ApplicationNativeAuthentication2FATestCase.java
new file mode 100644
index 00000000000..e3b6100e892
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/applicationNativeAuthentication/ApplicationNativeAuthentication2FATestCase.java
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
+ *
+ * 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.identity.integration.test.applicationNativeAuthentication;
+
+import com.icegreen.greenmail.util.GreenMailUtil;
+import io.restassured.http.ContentType;
+import io.restassured.response.ExtractableResponse;
+import io.restassured.response.Response;
+import jakarta.mail.Message;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.CookieSpecs;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.config.Lookup;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.cookie.CookieSpecProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.wso2.carbon.automation.engine.context.TestUserMode;
+import org.wso2.carbon.identity.application.common.model.idp.xsd.FederatedAuthenticatorConfig;
+import org.wso2.carbon.identity.application.common.model.idp.xsd.IdentityProvider;
+import org.wso2.identity.integration.common.clients.Idp.IdentityProviderMgtServiceClient;
+import org.wso2.identity.integration.test.oauth2.OAuth2ServiceAbstractIntegrationTest;
+import org.wso2.identity.integration.test.oidc.OIDCUtilTest;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AdvancedApplicationConfiguration;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationModel;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationResponseModel;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AuthenticationSequence;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.Authenticator;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.InboundProtocols;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
+import org.wso2.identity.integration.test.rest.api.user.common.model.Email;
+import org.wso2.identity.integration.test.rest.api.user.common.model.ListObject;
+import org.wso2.identity.integration.test.rest.api.user.common.model.Name;
+import org.wso2.identity.integration.test.rest.api.user.common.model.PatchOperationRequestObject;
+import org.wso2.identity.integration.test.rest.api.user.common.model.RoleItemAddGroupobj;
+import org.wso2.identity.integration.test.rest.api.user.common.model.UserObject;
+import org.wso2.identity.integration.test.restclients.SCIM2RestClient;
+import org.wso2.identity.integration.test.util.Utils;
+import org.wso2.identity.integration.test.utils.OAuth2Constant;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static io.restassured.RestAssured.given;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.AUTHENTICATOR;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.AUTHENTICATORS;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.AUTHENTICATOR_ID;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.AUTH_DATA_CODE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.AUTH_DATA_SESSION_STATE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.CODE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.CONFIDENTIAL;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.CONTENT_TYPE_APPLICATION_JSON;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.DESCRIPTION;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.DISPLAY_NAME;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.FAIL_INCOMPLETE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.FLOW_ID;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.FLOW_STATUS;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.FLOW_TYPE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.HREF;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.I18N_KEY;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.IDP;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.LINKS;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.MESSAGE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.MESSAGES;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.MESSAGE_ID;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.METADATA;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.NEXT_STEP;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.ORDER;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.PARAM;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.PARAMS;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.PROMPT_TYPE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.REQUIRED_PARAMS;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.RESPONSE_MODE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.STEP_TYPE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.SUCCESS_COMPLETED;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.TEST_APP_NAME;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.TEST_PASSWORD;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.TEST_USER_NAME;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.TRACE_ID;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.TYPE;
+import static org.wso2.identity.integration.test.applicationNativeAuthentication.Constants.UTF_8;
+
+/**
+ * Integration test class for testing the native authentication flow in an OAuth 2.0-enabled application.
+ * This test case extends {@link OAuth2ServiceAbstractIntegrationTest} and focuses on scenarios related
+ * to native authentication, covering the interaction between the application, authorization server, and user.
+ * The app contains basic as first authentication matrix and email otp as second authentication step.
+ */
+public class ApplicationNativeAuthentication2FATestCase extends OAuth2ServiceAbstractIntegrationTest {
+
+ private String appId;
+ private String flowId;
+ private String flowStatus;
+ private String authenticatorId;
+ private String href;
+ private JSONArray paramsArray;
+ private CloseableHttpClient client;
+ private String code;
+ protected SCIM2RestClient scim2RestClient;
+ private UserObject userObject;
+ private String userId;
+
+
+ @BeforeClass(alwaysRun = true)
+ public void testInit() throws Exception {
+
+ Utils.getMailServer().purgeEmailFromAllMailboxes();
+ super.init(TestUserMode.SUPER_TENANT_USER);
+
+ Lookup cookieSpecRegistry = RegistryBuilder.create()
+ .register(CookieSpecs.DEFAULT, new RFC6265CookieSpecProvider())
+ .build();
+ RequestConfig requestConfig = RequestConfig.custom()
+ .setCookieSpec(CookieSpecs.DEFAULT)
+ .build();
+ client = HttpClientBuilder.create()
+ .setDefaultCookieSpecRegistry(cookieSpecRegistry)
+ .setDefaultRequestConfig(requestConfig)
+ .build();
+
+ setSystemproperties();
+ scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo);
+ userObject = initUser();
+ createUser(userObject);
+ // Reset the idp cache object to remove effects from previous test cases.
+ resetResidentIDPCache();
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void atEnd() throws Exception {
+
+ deleteApp(appId);
+ deleteUser(userObject);
+ scim2RestClient = null;
+
+ // Nullifying attributes.
+ consumerKey = null;
+ consumerSecret = null;
+ appId = null;
+ flowId = null;
+ flowStatus = null;
+ code = null;
+ authenticatorId = null;
+ href = null;
+ paramsArray = null;
+ client.close();
+ restClient.closeHttpClient();
+ Utils.getMailServer().purgeEmailFromAllMailboxes();
+ }
+
+ private UserObject initUser() {
+
+ UserObject user = new UserObject();
+ user.setUserName(TEST_USER_NAME);
+ user.setPassword(TEST_PASSWORD);
+ user.setName(new Name().givenName(OIDCUtilTest.firstName).familyName(OIDCUtilTest.lastName));
+ user.addEmail(new Email().value(OIDCUtilTest.email));
+ return user;
+ }
+
+ /**
+ * Creates a user.
+ *
+ * @param user user instance.
+ * @throws Exception If an error occurred while creating a user.
+ */
+ private void createUser(UserObject user) throws Exception {
+
+ scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo);
+ userId = scim2RestClient.createUser(user);
+
+ RoleItemAddGroupobj rolePatchReqObject = new RoleItemAddGroupobj();
+ rolePatchReqObject.setOp(RoleItemAddGroupobj.OpEnum.ADD);
+ rolePatchReqObject.setPath("users");
+ rolePatchReqObject.addValue(new ListObject().value(userId));
+
+ String roleId = scim2RestClient.getRoleIdByName("everyone");
+ scim2RestClient.updateUserRole(new PatchOperationRequestObject().addOperations(rolePatchReqObject), roleId);
+ }
+
+ /**
+ * Deletes a user.
+ *
+ * @param user user instance.
+ * @throws Exception If an error occurred while deleting a user.
+ */
+ private void deleteUser(UserObject user) throws Exception {
+
+ log.info("Deleting User " + user.getUserName());
+ scim2RestClient.deleteUser(userId);
+ }
+
+ @Test(groups = "wso2.is", description = "Check Oauth2 application registration for default configurations.")
+ public void testRegisterApplication() throws Exception {
+
+ ApplicationResponseModel application = createApp();
+ Assert.assertNotNull(application, "OAuth App creation failed.");
+
+ OpenIDConnectConfiguration oidcConfig = getOIDCInboundDetailsOfApplication(application.getId());
+ consumerKey = oidcConfig.getClientId();
+ Assert.assertNotNull(consumerKey, "Application creation failed.");
+
+ appId = application.getId();
+ Assert.assertTrue(application.getAdvancedConfigurations().getEnableAPIBasedAuthentication(),
+ "API Base Authentication expected to false by default but set as true.");
+
+ }
+
+ @Test(groups = "wso2.is", description = "Send init authorize POST request.",
+ dependsOnMethods = "testRegisterApplication")
+ public void testSendInitAuthRequestPost() throws Exception {
+
+ HttpResponse response = sendPostRequestWithParameters(client, buildOAuth2Parameters(consumerKey),
+ OAuth2Constant.AUTHORIZE_ENDPOINT_URL);
+ Assert.assertNotNull(response, "Authorization request failed. Authorized response is null.");
+
+ String responseString = EntityUtils.toString(response.getEntity(), UTF_8);
+ EntityUtils.consume(response.getEntity());
+ JSONParser parser = new JSONParser();
+ JSONObject json = (JSONObject) parser.parse(responseString);
+ Assert.assertNotNull(json, "Client Native Authentication Init response is null.");
+ validInitClientNativeAuthnResponse(json);
+ }
+
+ @Test(groups = "wso2.is", description = "Send Basic authentication POST request.",
+ dependsOnMethods = "testSendInitAuthRequestPost")
+ public void testSendBasicAuthRequestWithFalseAuthenticator() throws Exception {
+
+ String body = "{\n" +
+ " \"flowId\": \"" + flowId + "\",\n" +
+ " \"selectedAuthenticator\": {\n" +
+ " \"authenticatorId\": \"" + "falseAuthenticatorId" + "\",\n" +
+ " \"params\": {\n" +
+ " \"username\": \"" + TEST_USER_NAME + "\",\n" +
+ " \"password\": \"" + TEST_PASSWORD + "\"\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ Response authnResponse = getResponseOfJSONPost( href, body, new HashMap<>());
+ ExtractableResponse extractableResponse = authnResponse.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_BAD_REQUEST)
+ .and()
+ .assertThat()
+ .header(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON)
+ .extract();
+ Assert.assertNotNull(extractableResponse, "Basic Authentication request failed. Authentication response is null.");
+
+ validateFailedBasicAuthenticationResponseBody(extractableResponse);
+ }
+
+ @Test(groups = "wso2.is", description = "Send Basic authentication POST request.",
+ dependsOnMethods = "testSendBasicAuthRequestWithFalseAuthenticator")
+ public void testSendBasicAuthRequestPostWithFalsePassword() throws Exception {
+
+ testSendInitAuthRequestPost();
+ String body = "{\n" +
+ " \"flowId\": \"" + flowId + "\",\n" +
+ " \"selectedAuthenticator\": {\n" +
+ " \"authenticatorId\": \"" + authenticatorId + "\",\n" +
+ " \"params\": {\n" +
+ " \"username\": \"" + TEST_USER_NAME + "\",\n" +
+ " \"password\": \"" + "FALSE_TEST_PASSWORD" + "\"\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ Response authnResponse = getResponseOfJSONPost( href, body, new HashMap<>());
+ ExtractableResponse extractableResponse = authnResponse.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_OK)
+ .and()
+ .assertThat()
+ .header(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON)
+ .extract();
+ Assert.assertNotNull(extractableResponse, "Basic Authentication request failed. Authentication response is null.");
+
+ validateBasicFailedAuthenticationResponseBody(extractableResponse);
+ }
+
+ @Test(groups = "wso2.is", description = "Send Basic authentication POST request.",
+ dependsOnMethods = "testSendBasicAuthRequestPostWithFalsePassword")
+ public void testSendBasicAuthRequestPost() throws Exception {
+
+ String body = "{\n" +
+ " \"flowId\": \"" + flowId + "\",\n" +
+ " \"selectedAuthenticator\": {\n" +
+ " \"authenticatorId\": \"" + authenticatorId + "\",\n" +
+ " \"params\": {\n" +
+ " \"username\": \"" + TEST_USER_NAME + "\",\n" +
+ " \"password\": \"" + TEST_PASSWORD + "\"\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ Response authnResponse = getResponseOfJSONPost( href, body, new HashMap<>());
+ ExtractableResponse extractableResponse = authnResponse.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_OK)
+ .and()
+ .assertThat()
+ .header(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON)
+ .extract();
+ Assert.assertNotNull(extractableResponse, "Basic Authentication request failed. Authentication response is null.");
+
+ validateBasicAuthenticationResponseBody(extractableResponse);
+ }
+
+ @Test(groups = "wso2.is", description = "Send Email OTP POST request.",
+ dependsOnMethods = "testSendBasicAuthRequestPost")
+ public void testSendEmailOTPRequestPost() {
+
+ String emailOTP = getOTPFromEmail();
+
+ if (emailOTP == null) {
+ Assert.fail("Unable to retrieve email otp from the email otp body");
+ }
+ String body = "{\n" +
+ " \"flowId\": \"" + flowId + "\",\n" +
+ " \"selectedAuthenticator\": {\n" +
+ " \"authenticatorId\": \"" + authenticatorId + "\",\n" +
+ " \"params\": {\n" +
+ " \"OTPCode\": \"" + emailOTP + "\"\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ Response authnResponse = getResponseOfJSONPost( href, body, new HashMap<>());
+ ExtractableResponse extractableResponse = authnResponse.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_OK)
+ .and()
+ .assertThat()
+ .header(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON)
+ .extract();
+ Assert.assertNotNull(extractableResponse, "Email OTP Authentication request failed. " +
+ "Authentication response is null.");
+
+ validateEmailOTPAuthenticationResponseBody(extractableResponse);
+ }
+
+ /**
+ * Validates specific fields in the JSON response of a basic authentication response.
+ *
+ * @param extractableResponse The ExtractableResponse containing the JSON response
+ */
+ private void validateEmailOTPAuthenticationResponseBody(ExtractableResponse extractableResponse) {
+
+ // Validate specific fields in the JSON response
+ flowStatus = extractableResponse
+ .jsonPath()
+ .getString(FLOW_STATUS);
+ Assert.assertEquals(flowStatus, SUCCESS_COMPLETED);
+
+ code = extractableResponse
+ .jsonPath()
+ .getString(AUTH_DATA_CODE);
+ Assert.assertNotNull(code, "Authorization Code is null in the authData");
+
+ Assert.assertNotNull(extractableResponse
+ .jsonPath()
+ .getString(AUTH_DATA_SESSION_STATE), "Session state is null in the authData");
+ }
+
+ /**
+ * Create Application with the given app configurations
+ *
+ * @return ApplicationResponseModel
+ * @throws Exception exception
+ */
+ private ApplicationResponseModel createApp() throws Exception {
+
+ ApplicationModel application = new ApplicationModel();
+
+ List grantTypes = new ArrayList<>();
+ Collections.addAll(grantTypes, OAuth2Constant.OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE);
+
+ List callBackUrls = new ArrayList<>();
+ Collections.addAll(callBackUrls, OAuth2Constant.CALLBACK_URL);
+
+ OpenIDConnectConfiguration oidcConfig = new OpenIDConnectConfiguration();
+ oidcConfig.setGrantTypes(grantTypes);
+ oidcConfig.setCallbackURLs(callBackUrls);
+ oidcConfig.setPublicClient(true);
+
+ InboundProtocols inboundProtocolsConfig = new InboundProtocols();
+ inboundProtocolsConfig.setOidc(oidcConfig);
+
+ application.setInboundProtocolConfiguration(inboundProtocolsConfig);
+ application.setName(TEST_APP_NAME);
+ application.advancedConfigurations(new AdvancedApplicationConfiguration());
+ application.getAdvancedConfigurations().setEnableAPIBasedAuthentication(true);
+ application.setAuthenticationSequence(new AuthenticationSequence()
+ .type(AuthenticationSequence.TypeEnum.USER_DEFINED)
+ .addStepsItem(new org.wso2.identity.integration.test.rest.api.server.application.management.
+ v1.model.AuthenticationStep()
+ .id(1)
+ .addOptionsItem(new Authenticator()
+ .idp("LOCAL")
+ .authenticator("BasicAuthenticator"))));
+ application.getAuthenticationSequence()
+ .addStepsItem(new org.wso2.identity.integration.test.rest.api.server.application.management.
+ v1.model.AuthenticationStep()
+ .id(2)
+ .addOptionsItem(new Authenticator()
+ .idp("LOCAL")
+ .authenticator("email-otp-authenticator")));
+ String appId = addApplication(application);
+ return getApplication(appId);
+ }
+
+ /**
+ * Builds a list of OAuth 2.0 parameters required for initiating the authorization process.
+ * The method constructs and returns a list of parameters necessary for initiating the OAuth 2.0 authorization process.
+ *
+ * @param consumerKey The client's unique identifier in the OAuth 2.0 system
+ * @return A list of NameValuePair representing the OAuth 2.0 parameters
+ */
+ private List buildOAuth2Parameters(String consumerKey) {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE,
+ OAuth2Constant.AUTHORIZATION_CODE_NAME));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_MODE, RESPONSE_MODE));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_CLIENT_ID, consumerKey));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, OAuth2Constant.CALLBACK_URL));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_SCOPE,
+ OAuth2Constant.OAUTH2_SCOPE_OPENID_WITH_INTERNAL_LOGIN));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_NONCE, UUID.randomUUID().toString()));
+
+ return urlParameters;
+ }
+
+ /**
+ * Validates the structure and content of a Client Native Authentication JSON response.
+ * The method checks for the presence of required keys and their expected types in the provided JSON.
+ * It verifies the format of the authentication flow, authenticators, metadata, and required parameters.
+ * If the JSON response is not in the expected format, the method asserts failures using JUnit's Assert.fail().
+ *
+ * @param json The JSON object representing the Client Native Authentication response
+ */
+ private void validInitClientNativeAuthnResponse(JSONObject json) {
+
+ // Check for the presence of required keys and their expected types
+ if (json.containsKey(FLOW_ID) && json.containsKey(FLOW_STATUS) && json.containsKey(FLOW_TYPE) &&
+ json.containsKey(NEXT_STEP) && json.containsKey(LINKS)) {
+
+ flowId = (String) json.get(FLOW_ID);
+ flowStatus = (String) json.get(FLOW_STATUS);
+
+ JSONObject nextStepNode = (JSONObject) json.get(NEXT_STEP);
+ if (nextStepNode.containsKey(STEP_TYPE) && nextStepNode.containsKey(AUTHENTICATORS)) {
+ JSONArray authenticatorsArray = (JSONArray) nextStepNode.get(AUTHENTICATORS);
+ if (!authenticatorsArray.isEmpty()) {
+ JSONObject authenticator = (JSONObject) authenticatorsArray.get(0);
+ if (authenticator.containsKey(AUTHENTICATOR_ID) && authenticator.containsKey(AUTHENTICATOR) &&
+ authenticator.containsKey(IDP) && authenticator.containsKey(METADATA) &&
+ authenticator.containsKey(REQUIRED_PARAMS)) {
+
+ authenticatorId = (String) authenticator.get(AUTHENTICATOR_ID);
+ JSONObject metadataNode = (JSONObject) authenticator.get(METADATA);
+ if (metadataNode.containsKey(PROMPT_TYPE) && metadataNode.containsKey(PARAMS)) {
+ paramsArray = (JSONArray) metadataNode.get(PARAMS);
+ if (paramsArray.isEmpty()) {
+ Assert.fail("Content of param for the authenticator is null in " +
+ "Client native authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("Params for the authenticator is null in " +
+ "Client native authentication JSON Response.");
+ }
+ }
+ } else {
+ Assert.fail("Authenticator is not expected format in Client native authentication");
+ }
+ } else {
+ Assert.fail("Authenticators in Client native authentication JSON Response is null, " +
+ "expecting list of Authentication.");
+ }
+ JSONArray links = (JSONArray) json.get(LINKS);
+ JSONObject link = (JSONObject) links.get(0);
+ if (link.containsKey(HREF)) {
+ href = link.get(HREF).toString();
+ } else {
+ Assert.fail("Link is not available for next step in Client native authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("Client native authentication JSON Response is not in expected format.");
+ }
+ }
+
+ /**
+ * Invoke given endpointUri for JSON POST request with given body, headers and Basic.
+ *
+ * @param endpointUri endpoint to be invoked
+ * @param body payload
+ * @param headers list of headers to be added to the request
+ * @return response
+ */
+ protected Response getResponseOfJSONPost(String endpointUri, String body, Map headers) {
+
+ return given()
+ .contentType(ContentType.JSON)
+ .headers(headers)
+ .body(body)
+ .when()
+ .post(endpointUri);
+ }
+
+ private String getOTPFromEmail() {
+
+ Assert.assertTrue(Utils.getMailServer().waitForIncomingEmail(10000, 1));
+ Message[] messages = Utils.getMailServer().getReceivedMessages();
+ String body = GreenMailUtil.getBody(messages[0]).replaceAll("=\r?\n", "");
+
+ String otpPattern = "One-Time Passcode:\\s*(\\d+)";
+ Pattern pattern = Pattern.compile(otpPattern);
+ Matcher matcher = pattern.matcher(body);
+
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ return null;
+ }
+
+ private void resetResidentIDPCache() throws Exception {
+
+ IdentityProviderMgtServiceClient superTenantIDPMgtClient =
+ new IdentityProviderMgtServiceClient(sessionCookie, backendURL);
+ IdentityProvider residentIdp = superTenantIDPMgtClient.getResidentIdP();
+
+ FederatedAuthenticatorConfig[] federatedAuthenticatorConfigs =
+ residentIdp.getFederatedAuthenticatorConfigs();
+ for (FederatedAuthenticatorConfig authenticatorConfig : federatedAuthenticatorConfigs) {
+ if (!authenticatorConfig.getName().equalsIgnoreCase("samlsso")) {
+ federatedAuthenticatorConfigs = (FederatedAuthenticatorConfig[])
+ ArrayUtils.removeElement(federatedAuthenticatorConfigs,
+ authenticatorConfig);
+ }
+ }
+ residentIdp.setFederatedAuthenticatorConfigs(federatedAuthenticatorConfigs);
+ superTenantIDPMgtClient.updateResidentIdP(residentIdp);
+ }
+
+ private void validateFailedBasicAuthenticationResponseBody(ExtractableResponse extractableResponse)
+ throws ParseException {
+
+ JSONParser parser = new JSONParser();
+ JSONObject json = (JSONObject) parser.parse(extractableResponse.body().asString());
+
+
+ // Check if the required keys are present
+ if (json.containsKey(CODE) && json.containsKey(MESSAGE) &&
+ json.containsKey(DESCRIPTION) && json.containsKey(TRACE_ID)) {
+
+ // Extract and validate the values (optional)
+ String code = (String) json.get(CODE);
+ String message = (String) json.get(MESSAGE);
+ String description = (String) json.get(DESCRIPTION);
+ String traceId = (String) json.get(TRACE_ID);
+
+ // Example validation: ensure no fields are null or empty
+ if (code == null || code.isEmpty()) {
+ Assert.fail("Code is missing or empty in the JSON response.");
+ }
+
+ if (message == null || message.isEmpty()) {
+ Assert.fail("Message is missing or empty in the JSON response.");
+ }
+
+ if (description == null || description.isEmpty()) {
+ Assert.fail("Description is missing or empty in the JSON response.");
+ }
+
+ if (traceId == null || traceId.isEmpty()) {
+ Assert.fail("TraceId is missing or empty in the JSON response.");
+ }
+
+ } else {
+ Assert.fail("JSON response is missing one or more required fields.");
+ }
+ }
+
+ private void validateBasicFailedAuthenticationResponseBody(ExtractableResponse extractableResponse)
+ throws ParseException {
+
+ JSONParser parser = new JSONParser();
+ JSONObject json = (JSONObject) parser.parse(extractableResponse.body().asString());
+
+ // Check for the presence of required keys and their expected types
+ if (json.containsKey(FLOW_ID) && json.containsKey(FLOW_STATUS) && json.containsKey(FLOW_TYPE) &&
+ json.containsKey(NEXT_STEP) && json.containsKey(LINKS)) {
+
+ Assert.assertEquals(flowId, (String) json.get(FLOW_ID), "Basic authentication " +
+ "JSON Response flow id is not same as init response.");
+ flowId = (String) json.get(FLOW_ID);
+ flowStatus = (String) json.get(FLOW_STATUS);
+ Assert.assertEquals(flowStatus, FAIL_INCOMPLETE);
+
+ JSONObject nextStepNode = (JSONObject) json.get(NEXT_STEP);
+ if (nextStepNode.containsKey(STEP_TYPE) && nextStepNode.containsKey(AUTHENTICATORS)
+ && nextStepNode.containsKey(MESSAGES)) {
+ JSONArray messagesArray = (JSONArray) nextStepNode.get(MESSAGES);
+ // Ensure the array is not empty
+ if (!messagesArray.isEmpty()) {
+ JSONObject messageObject = (JSONObject) messagesArray.get(0);
+
+ // Check for required fields within each message object
+ if (messageObject.containsKey(TYPE) && messageObject.containsKey(MESSAGE_ID) &&
+ messageObject.containsKey(MESSAGE) && messageObject.containsKey(I18N_KEY)) {
+
+ // Extract and validate values (optional)
+ String type = (String) messageObject.get(TYPE);
+ String messageId = (String) messageObject.get(MESSAGE_ID);
+ String message = (String) messageObject.get(MESSAGE);
+ String i18nKey = (String) messageObject.get(I18N_KEY);
+
+ // Example validation: Ensure none of the values are null or empty
+ if (type == null || type.isEmpty()) {
+ Assert.fail("Type is missing or empty in the messages array.");
+ }
+
+ if (messageId == null || messageId.isEmpty()) {
+ Assert.fail("Message ID is missing or empty in the messages array.");
+ }
+
+ if (message == null || message.isEmpty()) {
+ Assert.fail("Message is missing or empty in the messages array.");
+ }
+
+ if (i18nKey == null || i18nKey.isEmpty()) {
+ Assert.fail("i18nKey is missing or empty in the messages array.");
+ }
+
+ } else {
+ Assert.fail("A required field is missing in the message object.");
+ }
+ } else {
+ Assert.fail("Messages array is empty.");
+ }
+ } else {
+ Assert.fail("NextStep is missing required fields in Basic authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("Basic authentication JSON Response is missing required fields.");
+ }
+ }
+
+ private void validateBasicAuthenticationResponseBody(ExtractableResponse extractableResponse)
+ throws ParseException {
+
+ JSONParser parser = new JSONParser();
+ JSONObject json = (JSONObject) parser.parse(extractableResponse.body().asString());
+
+ // Check for the presence of required keys and their expected types
+ if (json.containsKey(FLOW_ID) && json.containsKey(FLOW_STATUS) && json.containsKey(FLOW_TYPE) &&
+ json.containsKey(NEXT_STEP) && json.containsKey(LINKS)) {
+
+ Assert.assertEquals(flowId, (String) json.get(FLOW_ID), "Basic authentication " +
+ "JSON Response flow id is not same as init response.");
+ flowId = (String) json.get(FLOW_ID);
+ flowStatus = (String) json.get(FLOW_STATUS);
+
+ JSONObject nextStepNode = (JSONObject) json.get(NEXT_STEP);
+ if (nextStepNode.containsKey(STEP_TYPE) && nextStepNode.containsKey(AUTHENTICATORS)) {
+ JSONArray authenticatorsArray = (JSONArray) nextStepNode.get(AUTHENTICATORS);
+ if (!authenticatorsArray.isEmpty()) {
+ JSONObject authenticator = (JSONObject) authenticatorsArray.get(0);
+ if (authenticator.containsKey(AUTHENTICATOR_ID) && authenticator.containsKey(AUTHENTICATOR) &&
+ authenticator.containsKey(IDP) && authenticator.containsKey(METADATA) &&
+ authenticator.containsKey(REQUIRED_PARAMS)) {
+
+ authenticatorId = (String) authenticator.get(AUTHENTICATOR_ID);
+ JSONObject metadataNode = (JSONObject) authenticator.get(METADATA);
+ if (metadataNode.containsKey(PROMPT_TYPE) && metadataNode.containsKey(PARAMS)) {
+ JSONArray paramsArray = (JSONArray) metadataNode.get(PARAMS);
+ if (!paramsArray.isEmpty()) {
+ JSONObject param = (JSONObject) paramsArray.get(0);
+ if (!param.containsKey(PARAM) || !param.containsKey(TYPE) ||
+ !param.containsKey(ORDER) || !param.containsKey(I18N_KEY) ||
+ !param.containsKey(DISPLAY_NAME) || !param.containsKey(CONFIDENTIAL)) {
+ Assert.fail("Param for the authenticator is not in the expected format.");
+ }
+
+ } else {
+ Assert.fail("Params for the authenticator is empty in Basic authentication " +
+ "JSON Response.");
+ }
+ } else {
+ Assert.fail("Metadata for the authenticator is missing required fields in Basic " +
+ "authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("Authenticator is missing required fields in Basic authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("Authenticators list is empty in Basic authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("NextStep is missing required fields in Basic authentication JSON Response.");
+ }
+
+ JSONArray linksArray = (JSONArray) json.get(LINKS);
+ if (!linksArray.isEmpty()) {
+ JSONObject link = (JSONObject) linksArray.get(0);
+ if (!link.containsKey(HREF)) {
+ Assert.fail("Href for the link is missing in Client native authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("Links array is empty in Client native authentication JSON Response.");
+ }
+ } else {
+ Assert.fail("Basic authentication JSON Response is missing required fields.");
+ }
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/applicationNativeAuthentication/Constants.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/applicationNativeAuthentication/Constants.java
index 63ce5c8214a..a524936a27f 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/applicationNativeAuthentication/Constants.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/applicationNativeAuthentication/Constants.java
@@ -60,4 +60,15 @@ public class Constants {
public static final String SUCCESS_COMPLETED = "SUCCESS_COMPLETED";
public static final String AUTH_DATA_CODE = "authData.code";
public static final String AUTH_DATA_SESSION_STATE = "authData.session_state";
+ public static final String PARAM = "param";
+ public static final String TYPE = "type";
+ public static final String ORDER = "order";
+ public static final String I18N_KEY = "i18nKey";
+ public static final String DISPLAY_NAME = "displayName";
+ public static final String CONFIDENTIAL = "confidential";
+ public static final String MESSAGE = "message";
+ public static final String DESCRIPTION = "description";
+ public static final String MESSAGE_ID = "messageId";
+ public static final String MESSAGES = "messages";
+ public static final String FAIL_INCOMPLETE = "FAIL_INCOMPLETE";
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/AdaptiveScriptInitializerTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/AdaptiveScriptInitializerTestCase.java
deleted file mode 100644
index fbb62b99981..00000000000
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/AdaptiveScriptInitializerTestCase.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2022 WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
- *
- * WSO2 Inc. 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.identity.integration.test.auth;
-
-import java.io.File;
-
-import org.testng.annotations.AfterTest;
-import org.testng.annotations.BeforeTest;
-import org.wso2.carbon.automation.extensions.servers.utils.ServerLogReader;
-import org.wso2.carbon.integration.common.utils.exceptions.AutomationUtilException;
-import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager;
-
-/**
- * Initiation Test for adaptive authentication.
- */
-public class AdaptiveScriptInitializerTestCase extends AbstractAdaptiveAuthenticationTestCase {
-
- private ServerConfigurationManager serverConfigurationManager;
-
- private int javaVersion;
- private static String enableInfo = "Adaptive authentication successfully enabled.";
- private static String disableInfo = "Adaptive authentication successfully disabled.";
-
- @BeforeTest(alwaysRun = true)
- public void testInit() throws Exception {
-
- super.init();
- serverConfigurationManager = new ServerConfigurationManager(isServer);
- javaVersion = getJavaVersion();
- // Download OpenJDK Nashorn only if the JDK version is Higher or Equal to 15.
- if (javaVersion >= 15) {
- runAdaptiveAuthenticationDependencyScript(false);
- }
- }
-
- /**
- * Get Java Major Version from System Property.
- *
- * @return Java Major Version
- */
- private int getJavaVersion() {
-
- String version = System.getProperty("java.version");
- if (version.startsWith("1.")) {
- version = version.substring(2, 3);
- } else {
- int dot = version.indexOf(".");
- if (dot != -1) {
- version = version.substring(0, dot);
- }
- }
- return Integer.parseInt(version);
- }
-
- private void runAdaptiveAuthenticationDependencyScript(boolean disable) {
-
- ServerLogReader inputStreamHandler;
- ServerLogReader errorStreamHandler;
- String targetFolder = System.getProperty("carbon.home");
- String scriptFolder = getTestArtifactLocation() + File.separator;
- Process tempProcess = null;
- File scriptFile = new File(scriptFolder);
- Runtime runtime = Runtime.getRuntime();
-
- try {
- if (System.getProperty("os.name").toLowerCase().contains("windows")) {
- log.info("Operating System is Windows. Executing batch script");
- if (disable) {
- // TODO https://github.com/wso2/product-is/issues/14301
- restartServer();
- tempProcess = runtime.exec(
- new String[] { "cmd", "/c", "adaptive.bat", targetFolder, "DISABLE" }, null, scriptFile);
- } else {
- tempProcess = runtime.exec(
- new String[] { "cmd", "/c", "adaptive.bat", targetFolder }, null, scriptFile);
- }
- errorStreamHandler = new ServerLogReader("errorStream",
- tempProcess.getErrorStream());
- inputStreamHandler = new ServerLogReader("inputStream",
- tempProcess.getInputStream());
- inputStreamHandler.start();
- errorStreamHandler.start();
- boolean runStatus = waitForMessage(inputStreamHandler, disable);
- log.info("Status Message : " + runStatus);
- restartServer();
- } else {
- log.info("Operating system is not windows. Executing shell script");
- if (disable) {
- tempProcess = runtime.getRuntime().exec(
- new String[] { "/bin/bash", "adaptive.sh", targetFolder, "DISABLE" }, null, scriptFile);
- } else {
- tempProcess = runtime.getRuntime().exec(
- new String[] { "/bin/bash", "adaptive.sh", targetFolder }, null, scriptFile);
- }
- errorStreamHandler = new ServerLogReader("errorStream",
- tempProcess.getErrorStream());
- inputStreamHandler = new ServerLogReader("inputStream",
- tempProcess.getInputStream());
- inputStreamHandler.start();
- errorStreamHandler.start();
- boolean runStatus = waitForMessage(inputStreamHandler, disable);
- log.info("Status Message : " + runStatus);
- restartServer();
- }
- } catch (Exception e) {
- log.error("Failed to execute adaptive authentication dependency script", e);
- } finally {
- if (tempProcess != null) {
- tempProcess.destroy();
- }
- }
- }
-
- private void restartServer() throws AutomationUtilException {
-
- serverConfigurationManager.restartGracefully();
- }
-
- private boolean waitForMessage(ServerLogReader inputStreamHandler, boolean disable) {
- long time = System.currentTimeMillis() + 60 * 1000;
- String message = enableInfo;
- if (disable) {
- message = disableInfo;
- }
- while (System.currentTimeMillis() < time) {
- if (inputStreamHandler.getOutput().contains(message)) {
- return true;
- }
- }
- return false;
- }
-
- @AfterTest(alwaysRun = true)
- public void resetUserstoreConfig() throws Exception {
-
- super.init();
- javaVersion = (javaVersion == 0) ? getJavaVersion() : javaVersion;
- if (javaVersion >= 15) {
- runAdaptiveAuthenticationDependencyScript(false);
- }
- serverConfigurationManager.restoreToLastConfiguration(false);
- }
-}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/NashornAdaptiveScriptInitializerTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/NashornAdaptiveScriptInitializerTestCase.java
index 3d9804e9328..5788b86bd02 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/NashornAdaptiveScriptInitializerTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/NashornAdaptiveScriptInitializerTestCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
+ * Copyright (c) 2022 WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
@@ -18,38 +18,138 @@
package org.wso2.identity.integration.test.auth;
+import java.io.File;
+
+import org.apache.commons.logging.Log;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
+import org.wso2.carbon.automation.engine.frameworkutils.FrameworkPathUtil;
+import org.wso2.carbon.automation.extensions.servers.utils.ServerLogReader;
+import org.wso2.carbon.integration.common.utils.exceptions.AutomationUtilException;
import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager;
import org.wso2.carbon.utils.CarbonUtils;
-import org.wso2.identity.integration.common.utils.ISIntegrationTest;
+import org.wso2.identity.integration.test.util.Utils;
-import java.io.File;
+/**
+ * Initiation Test for adaptive authentication.
+ */
+public class NashornAdaptiveScriptInitializerTestCase extends AbstractAdaptiveAuthenticationTestCase {
-public class NashornAdaptiveScriptInitializerTestCase extends ISIntegrationTest {
+ private ServerConfigurationManager serverConfigurationManager;
- private ServerConfigurationManager scm;
- private File defaultConfigFile;
+ private int javaVersion;
@BeforeTest(alwaysRun = true)
- public void initScriptEngineConfig() throws Exception {
+ public void testInit() throws Exception {
super.init();
+ serverConfigurationManager = new ServerConfigurationManager(isServer);
String carbonHome = CarbonUtils.getCarbonHome();
- defaultConfigFile = getDeploymentTomlFile(carbonHome);
+ File defaultConfigFile = getDeploymentTomlFile(carbonHome);
+
+ javaVersion = Utils.getJavaVersion();
+ String identityNewResourceFileName = "nashorn_script_engine_config.toml";
+
+ if (javaVersion >= 15) {
+ // Download OpenJDK Nashorn only if the JDK version is Higher or Equal to 15.
+ runAdaptiveAuthenticationDependencyScript(false, serverConfigurationManager, log);
+ identityNewResourceFileName = "openjdknashorn_script_engine_config.toml";
+ }
+
File scriptEngineConfigFile = new File(
getISResourceLocation() + File.separator + "scriptEngine" + File.separator +
- "nashorn_script_engine_config.toml");
- scm = new ServerConfigurationManager(isServer);
- scm.applyConfiguration(scriptEngineConfigFile, defaultConfigFile, true, true);
+ identityNewResourceFileName);
+ serverConfigurationManager.applyConfigurationWithoutRestart(scriptEngineConfigFile, defaultConfigFile, true);
+ serverConfigurationManager.restartGracefully();
+ }
+
+ protected static void runAdaptiveAuthenticationDependencyScript(boolean disable, ServerConfigurationManager scm, Log logger) {
+
+ ServerLogReader inputStreamHandler;
+ ServerLogReader errorStreamHandler;
+ String targetFolder = System.getProperty("carbon.home");
+ String scriptFolder = FrameworkPathUtil.getSystemResourceLocation() + File.separator;
+ Process tempProcess = null;
+ File scriptFile = new File(scriptFolder);
+ Runtime runtime = Runtime.getRuntime();
+
+ try {
+ if (System.getProperty("os.name").toLowerCase().contains("windows")) {
+ logger.info("Operating System is Windows. Executing batch script");
+ if (disable) {
+ /*
+ Restarting before the excution to release the locks on nashorn
+ and asm-util jars in the dropins directory.
+ */
+ scm.restartGracefully();
+ tempProcess = runtime.exec(
+ new String[]{"cmd", "/c", "adaptive.bat", targetFolder, "DISABLE"}, null, scriptFile);
+ } else {
+ tempProcess = runtime.exec(
+ new String[]{"cmd", "/c", "adaptive.bat", targetFolder}, null, scriptFile);
+ }
+ errorStreamHandler = new ServerLogReader("errorStream", tempProcess.getErrorStream());
+ inputStreamHandler = new ServerLogReader("inputStream", tempProcess.getInputStream());
+ inputStreamHandler.start();
+ errorStreamHandler.start();
+ boolean runStatus = waitForMessage(inputStreamHandler, disable);
+ logger.info("Status Message : " + runStatus);
+ scm.restartGracefully();
+ } else {
+ logger.info("Operating system is not windows. Executing shell script");
+ if (disable) {
+ tempProcess = Runtime.getRuntime().exec(
+ new String[]{"/bin/bash", "adaptive.sh", targetFolder, "DISABLE"}, null, scriptFile);
+ } else {
+ tempProcess = Runtime.getRuntime().exec(
+ new String[]{"/bin/bash", "adaptive.sh", targetFolder}, null, scriptFile);
+ }
+ errorStreamHandler = new ServerLogReader("errorStream", tempProcess.getErrorStream());
+ inputStreamHandler = new ServerLogReader("inputStream", tempProcess.getInputStream());
+ inputStreamHandler.start();
+ errorStreamHandler.start();
+ boolean runStatus = waitForMessage(inputStreamHandler, disable);
+ logger.info("Status Message : " + runStatus);
+ scm.restartGracefully();
+ }
+ } catch (Exception e) {
+ logger.error("Failed to execute adaptive authentication dependency script", e);
+ } finally {
+ if (tempProcess != null) {
+ tempProcess.destroy();
+ }
+ }
+ }
+
+ private void restartServer() throws AutomationUtilException {
+
+ serverConfigurationManager.restartGracefully();
+ }
+
+ private static boolean waitForMessage(ServerLogReader inputStreamHandler, boolean disable) {
+
+ long time = System.currentTimeMillis() + 60 * 1000;
+ String message = "Adaptive authentication successfully enabled.";
+ if (disable) {
+ message = "Adaptive authentication successfully disabled.";
+ }
+ while (System.currentTimeMillis() < time) {
+ if (inputStreamHandler.getOutput().contains(message)) {
+ return true;
+ }
+ }
+ return false;
}
@AfterTest(alwaysRun = true)
public void resetScriptEngineConfig() throws Exception {
super.init();
- scm.restoreToLastConfiguration(false);
- scm.restartGracefully();
+ serverConfigurationManager.restoreToLastConfiguration(false);
+ javaVersion = (javaVersion == 0) ? Utils.getJavaVersion() : javaVersion;
+ if (javaVersion >= 15) {
+ runAdaptiveAuthenticationDependencyScript(true, serverConfigurationManager, log);
+ }
+ restartServer();
}
-
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/RiskBasedLoginTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/RiskBasedLoginTestCase.java
index 860a8421dd3..78793e9945f 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/RiskBasedLoginTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/auth/RiskBasedLoginTestCase.java
@@ -94,13 +94,10 @@ public class RiskBasedLoginTestCase extends AbstractAdaptiveAuthenticationTestCa
private ApplicationManagementServiceClient applicationManagementServiceClient;
private WebAppAdminClient webAppAdminClient;
private CookieStore cookieStore = new BasicCookieStore();
- private Lookup cookieSpecRegistry;
- private RequestConfig requestConfig;
private HttpClient client;
private HttpResponse response;
- private List consentParameters = new ArrayList<>();
private ServerConfigurationManager serverConfigurationManager;
- private IdentityProvider superTenantResidentIDP;
+ private boolean openJDKNashornEnabled = false;
private Map userRiskScores = new HashMap<>();
@@ -110,7 +107,7 @@ public class RiskBasedLoginTestCase extends AbstractAdaptiveAuthenticationTestCa
@BeforeClass(alwaysRun = true)
@Parameters({"scriptEngine"})
- public void testInit(@Optional("nashorn") String scriptEngine) throws Exception {
+ public void testInit(@Optional("graaljs") String scriptEngine) throws Exception {
super.init();
@@ -145,7 +142,7 @@ public void testInit(@Optional("nashorn") String scriptEngine) throws Exception
String authenticatorWebappPathString = Utils.getResidentCarbonHome()
+ File.separator + "repository" + File.separator + "deployment" + File.separator
+ "server" + File.separator + "webapps" + File.separator + "sample-auth";
- waitForWebappToDeploy(authenticatorWebappPathString, 120000L);
+ waitForWebappToDeploy(authenticatorWebappPathString);
log.info("Copied the demo authenticator war file to " + authenticatorWarPathString);
Assert.assertTrue(Files.exists(Paths.get(authenticatorWarPathString)), "Demo Authenticator war is not copied " +
@@ -168,10 +165,10 @@ public void testInit(@Optional("nashorn") String scriptEngine) throws Exception
configContext);
webAppAdminClient = new WebAppAdminClient(backendURL, sessionCookie);
- cookieSpecRegistry = RegistryBuilder.create()
+ Lookup cookieSpecRegistry = RegistryBuilder.create()
.register(CookieSpecs.DEFAULT, new RFC6265CookieSpecProvider())
.build();
- requestConfig = RequestConfig.custom()
+ RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.build();
client = HttpClientBuilder.create()
@@ -191,16 +188,16 @@ public void testInit(@Optional("nashorn") String scriptEngine) throws Exception
microserviceServer = MicroserviceUtil.initMicroserviceServer();
MicroserviceUtil.deployService(microserviceServer, this);
- superTenantResidentIDP = superTenantIDPMgtClient.getResidentIdP();
+ IdentityProvider superTenantResidentIDP = superTenantIDPMgtClient.getResidentIdP();
updateResidentIDPProperty(superTenantResidentIDP, "adaptive_authentication.analytics.receiver",
"http://localhost:" + microserviceServer.getPort());
userRiskScores.put(userInfo.getUserName(), 0);
}
- private void changeAdaptiveAuthenticationScript(String scriptFileName) throws Exception {
+ private void changeAdaptiveAuthenticationScript() throws Exception {
- String script = getConditionalAuthScript(scriptFileName);
+ String script = getConditionalAuthScript("RiskBasedLoginScriptPayload.js");
serviceProvider.getLocalAndOutBoundAuthenticationConfig().getAuthenticationScriptConfig().setContent(script);
applicationManagementServiceClient.updateApplicationData(serviceProvider);
}
@@ -209,7 +206,14 @@ private void changeISConfiguration(String scriptEngine) throws Exception {
String identityNewResourceFileName = "identity_new_resource.toml";
if (scriptEngine.equalsIgnoreCase("nashorn")) {
- identityNewResourceFileName = "identity_new_resource_nashorn.toml";
+ if (Utils.getJavaVersion() >= 15) {
+ identityNewResourceFileName = "identity_new_resource_openjdknashorn.toml";
+ NashornAdaptiveScriptInitializerTestCase.runAdaptiveAuthenticationDependencyScript(false,
+ serverConfigurationManager, log);
+ openJDKNashornEnabled = true;
+ } else {
+ identityNewResourceFileName = "identity_new_resource_nashorn.toml";
+ }
}
String carbonHome = Utils.getResidentCarbonHome();
@@ -224,13 +228,17 @@ private void changeISConfiguration(String scriptEngine) throws Exception {
private void resetISConfiguration() throws Exception {
serverConfigurationManager.restoreToLastConfiguration(false);
+ if (openJDKNashornEnabled) {
+ NashornAdaptiveScriptInitializerTestCase.runAdaptiveAuthenticationDependencyScript(true,
+ serverConfigurationManager, log);
+ }
}
- private void waitForWebappToDeploy(String authenticatorWebappPathString, long timeout) {
+ private void waitForWebappToDeploy(String authenticatorWebappPathString) {
long startTime = System.currentTimeMillis();
- while (System.currentTimeMillis() - startTime < timeout) {
+ while (System.currentTimeMillis() - startTime < 120000L) {
if (Files.exists(Paths.get(authenticatorWebappPathString))) {
log.info(authenticatorWebappPathString + " deployed successfully.");
break;
@@ -376,7 +384,7 @@ public void testAuthenticationForRisk() throws Exception {
@Test(groups = "wso2.is", description = "Check conditional authentication flow.")
public void testAuthenticationForRiskWithComplexPayload() throws Exception {
- changeAdaptiveAuthenticationScript("RiskBasedLoginScriptPayload.js");
+ changeAdaptiveAuthenticationScript();
cookieStore.clear();
response = loginWithOIDC(PRIMARY_IS_APPLICATION_NAME, consumerKey, client);
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/base/MockOIDCIdentityProvider.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/base/MockOIDCIdentityProvider.java
new file mode 100644
index 00000000000..59533900bd1
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/base/MockOIDCIdentityProvider.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
+ *
+ * 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.identity.integration.test.base;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
+import com.github.tomakehurst.wiremock.extension.ResponseTransformerV2;
+import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
+import com.github.tomakehurst.wiremock.http.Response;
+import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.JWSSigner;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import org.wso2.identity.integration.test.util.Utils;
+
+import java.io.FileInputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.containing;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.matching;
+import static com.github.tomakehurst.wiremock.client.WireMock.notContaining;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
+
+/**
+ * Mock OIDC Identity Provider for testing OIDC flows.
+ */
+public class MockOIDCIdentityProvider {
+
+ public static final String MOCK_IDP_AUTHORIZE_ENDPOINT = "https://localhost:8089/authorize";
+ public static final String MOCK_IDP_TOKEN_ENDPOINT = "https://localhost:8089/token";
+ public static final String MOCK_IDP_LOGOUT_ENDPOINT = "https://localhost:8089/oidc/logout";
+ public static final String MOCK_IDP_CLIENT_ID = "mockIdPClientID";
+ public static final String MOCK_IDP_CLIENT_SECRET = "mockIdPClientSecret";
+
+ private WireMockServer wireMockServer;
+ private final AtomicReference authorizationCode = new AtomicReference<>();
+
+ public void start() {
+
+ wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig()
+ .httpsPort(8089)
+ .keystorePath(Paths.get(Utils.getResidentCarbonHome(), "repository", "resources", "security",
+ "wso2carbon.p12").toAbsolutePath().toString())
+ .keystorePassword("wso2carbon")
+ .keyManagerPassword("wso2carbon")
+ .extensions(
+ new ResponseTemplateTransformer(null, true, null, null),
+ new ResponseTransformerV2() {
+ @Override
+ public Response transform(Response response, ServeEvent serveEvent) {
+ // Extract the code parameter from the redirect URL
+ String locationHeader = response.getHeaders().getHeader("Location").firstValue();
+ String codeParam = locationHeader.split("code=")[1].split("&")[0];
+
+ // Store the authorization code
+ authorizationCode.set(codeParam);
+ return response;
+ }
+
+ @Override
+ public boolean applyGlobally() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "authz-code-transformer";
+ }
+ }));
+
+ wireMockServer.start();
+
+ // Configure the mock OIDC endpoints
+ configureMockEndpoints();
+ }
+
+ public void stop() {
+
+ if (wireMockServer != null) {
+ wireMockServer.stop();
+ }
+ }
+
+ private void configureMockEndpoints() {
+
+ wireMockServer.stubFor(post(urlEqualTo("/token"))
+ .withRequestBody(notContaining("grant_type=")
+ .or(notContaining("code="))
+ .or(notContaining("redirect_uri=")))
+ .willReturn(aResponse()
+ .withStatus(400)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{ \"error\": \"invalid_request\", \"error_description\": " +
+ "\"Missing required parameter\" }")));
+
+ try {
+ wireMockServer.stubFor(post(urlEqualTo("/token"))
+ .withRequestBody(containing("grant_type=authorization_code"))
+ .withRequestBody(containing("code="))
+ .withRequestBody(containing("redirect_uri="))
+ .withRequestBody(containing("client_secret="+ MOCK_IDP_CLIENT_SECRET))
+ .withRequestBody(containing("client_id=" + MOCK_IDP_CLIENT_ID))
+ .willReturn(aResponse()
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"access_token\": \"mock_access_token\", \"token_type\": \"Bearer\", " +
+ "\"expires_in\": 3600, \"id_token\": \"" + buildIdToken() + "\" }")));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ wireMockServer.stubFor(get(urlPathEqualTo("/authorize"))
+ .withQueryParam("response_type", matching(".*"))
+ .withQueryParam("redirect_uri", matching(".*"))
+ .withQueryParam("state", matching(".*"))
+ .withQueryParam("nonce", matching(".*"))
+ .withQueryParam("client_id", matching(MOCK_IDP_CLIENT_ID))
+ .withQueryParam("scope", matching(".*"))
+ .willReturn(aResponse()
+ .withTransformers("response-template", "authz-code-transformer")
+ .withStatus(302)
+ .withHeader("Location",
+ "{{request.query.redirect_uri}}?session_state=mockid&code="
+ + java.util.UUID.randomUUID() + "&state={{request.query.state}}")));
+
+ wireMockServer.stubFor(get(urlPathEqualTo("/oidc/logout"))
+ .withQueryParam("state", matching(".*"))
+ .withQueryParam("post_logout_redirect_uri", matching(".*"))
+ .withQueryParam("id_token_hint", matching(".*"))
+ .willReturn(aResponse()
+ .withTransformers("response-template")
+ .withStatus(302)
+ .withHeader("Location",
+ "{{request.query.post_logout_redirect_uri}}?state={{request.query.state}}")));
+ }
+
+ public void verifyForAuthzCodeFlow() {
+
+ wireMockServer.verify(postRequestedFor(urlPathEqualTo("/token"))
+ .withRequestBody(containing("grant_type=authorization_code"))
+ .withRequestBody(containing("code=" + authorizationCode.get())));
+ wireMockServer.verify(getRequestedFor(urlPathEqualTo("/authorize")));
+ }
+
+ public void verifyForLogoutFlow() {
+
+ wireMockServer.verify(getRequestedFor(urlPathEqualTo("/oidc/logout")));
+ }
+
+ private String buildIdToken() throws Exception {
+
+ KeyStore wso2KeyStore = getKeyStoreFromFile("wso2carbon.p12", "wso2carbon",
+ Utils.getResidentCarbonHome());
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) wso2KeyStore.getKey("wso2carbon", "wso2carbon".toCharArray());
+
+ JWSSigner signer = new RSASSASigner(rsaPrivateKey);
+
+ // Prepare JWT with claims set
+ JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+ .issuer("https://localhost:8089/token")
+ .subject("61b935a1-1915-4792-8916-99c59d03c54a")
+ .audience("LzWfxDK_7LSGxfuL3BlRdXUGEJYa")
+ .claim("azp", "LzWfxDK_7LSGxfuL3BlRdXUGEJYa")
+ .claim("org_id", "10084a8d-113f-4211-a0d5-efe36b082211")
+ .claim("org_name", "Super")
+ .claim("amr", new String[]{"BasicAuthenticator"})
+ .claim("c_hash", "3eh6RwdVWxGQEljI7l9K3g")
+ .claim("at_hash", "zZ5nLASTkVRWrcCelPOHw")
+ .claim("sid", "05759c14-d0bc-414a-931c-b7ffba55b2c3")
+ .claim("jti", "37803fb8-f1f1-4eac-8ed2-5067349664fc")
+ .claim("isk", "9ab97ab343161334c9432d117e8da73211949aacce8c5d1c0ba8d6c75e0782c4")
+ .issueTime(new Date())
+ .notBeforeTime(new Date())
+ .build();
+
+ SignedJWT signedJWT = new SignedJWT(
+ new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(getKeyId(rsaPrivateKey)).build(), claimsSet);
+ signedJWT.sign(signer);
+ return signedJWT.serialize();
+ }
+
+ private KeyStore getKeyStoreFromFile(String keystoreName, String password, String home) throws Exception {
+
+ Path tenantKeystorePath = Paths.get(home, "repository", "resources", "security", keystoreName);
+ FileInputStream file = new FileInputStream(tenantKeystorePath.toString());
+ KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keystore.load(file, password.toCharArray());
+ return keystore;
+ }
+
+ private String getKeyId(RSAPrivateKey privateKey) throws Exception {
+
+ java.security.MessageDigest sha256 = java.security.MessageDigest.getInstance("SHA-256");
+ byte[] keyBytes = privateKey.getEncoded();
+ byte[] hash = sha256.digest(keyBytes);
+ return java.util.Base64.getUrlEncoder().withoutPadding().encodeToString(hash);
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/idp/mgt/IdentityProviderMgtServiceTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/idp/mgt/IdentityProviderMgtServiceTestCase.java
index fd106d5b634..0176d8e8551 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/idp/mgt/IdentityProviderMgtServiceTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/idp/mgt/IdentityProviderMgtServiceTestCase.java
@@ -47,7 +47,7 @@ public class IdentityProviderMgtServiceTestCase extends ISIntegrationTest {
private String testIdpName = "TestIDPProvider";
private String testIdpNameSearch = "SearchTestIDPProviderTest";
private String updatedTestIdpName = "UpdatedTestIDPProvider";
- private String testFedAuthName = "OpenIDAuthenticator";
+ private String testFedAuthName = "OpenIDConnectAuthenticator";
//Resident idp default values
private boolean residentIdpEnable;
@@ -159,7 +159,7 @@ public void testGetResidentIdP() throws Exception {
public void testAddIdp() throws Exception {
String testIdpDescription = "This is test identity provider";
String testIdpRealmId = "localhost";
- String testFedAuthDispName = "openid";
+ String testFedAuthDispName = "openidConnect";
String testFedAuthPropName = "OpenIdUrl";
String testFedAuthPropValue = "https://testDomain:9853/openid";
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2PushedAuthRequestTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2PushedAuthRequestTestCase.java
index 75e6306fcef..5317405e78b 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2PushedAuthRequestTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2PushedAuthRequestTestCase.java
@@ -17,6 +17,7 @@
*/
package org.wso2.identity.integration.test.oauth2;
+import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.CookieSpecs;
@@ -44,6 +45,7 @@
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
import org.wso2.identity.integration.test.utils.OAuth2Constant;
+import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -121,9 +123,11 @@ public void testSendPar() throws Exception {
urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, OAuth2Constant.CALLBACK_URL));
urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE,
OAuth2Constant.OAUTH2_GRANT_TYPE_CODE));
- String response = responsePost(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
JSONParser parser = new JSONParser();
- JSONObject jsonResponse = (JSONObject) parser.parse(response);
+ JSONObject jsonResponse = (JSONObject) parser.parse(responseString);
if (jsonResponse == null) {
throw new Exception("Error occurred while getting the response.");
}
@@ -139,8 +143,10 @@ public void testSendAuthorize() throws Exception {
List urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair(REQUEST_URI, requestUri));
urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, consumerKey));
- String response = responsePost(OAuth2Constant.AUTHORIZE_ENDPOINT_URL, urlParameters);
- Assert.assertNotNull(response, "Authorized response is null");
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
+ Assert.assertNotNull(responseString, "Authorized response is null");
}
@Test(groups = "wso2.is", description = "Send PAR with openid request object", dependsOnMethods =
@@ -154,9 +160,11 @@ public void testSendParWithRequestObject() throws Exception {
OAuth2Constant.OAUTH2_GRANT_TYPE_CODE));
urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH_OIDC_REQUEST, REQUEST));
urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_SCOPE, OAuth2Constant.OAUTH2_SCOPE_OPENID));
- String response = responsePost(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
JSONParser parser = new JSONParser();
- JSONObject jsonResponse = (JSONObject) parser.parse(response);
+ JSONObject jsonResponse = (JSONObject) parser.parse(responseString);
if (jsonResponse == null) {
throw new Exception("Error occurred while getting the response.");
}
@@ -166,16 +174,148 @@ public void testSendParWithRequestObject() throws Exception {
Assert.assertNotNull(expiryTime, "expiry_time is null");
}
- private String responsePost(String endpoint, List postParameters)
- throws Exception {
+ @Test(groups = "wso2.is", description = "Send authorize user request with invalid client id",
+ dependsOnMethods = "testSendPar")
+ public void testSendAuthorizeWithInvalidClient() throws Exception {
- HttpPost httpPost = new HttpPost(endpoint);
- httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
- httpPost.setEntity(new UrlEncodedFormEntity(postParameters));
- HttpResponse response = client.execute(httpPost);
- String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
- EntityUtils.consume(response.getEntity());
- return responseString;
+ testSendPar();
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(REQUEST_URI, requestUri));
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, "invalid_client_id"));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.AUTHORIZE_ENDPOINT_URL, urlParameters);
+ String locationHeader = response.getFirstHeader("Location") != null ?
+ response.getFirstHeader("Location").getValue() : null;
+
+ Assert.assertNotNull(locationHeader, "Location header from the authz response is null");
+ Assert.assertTrue(StringUtils.contains(locationHeader, "oauthErrorMsg=par.client.id.not.match"));
+ }
+
+ @Test(groups = "wso2.is", description = "Send authorize user request with invalid request uri",
+ dependsOnMethods = "testSendAuthorizeWithInvalidClient")
+ public void testSendAuthorizeWithInvalidRequestURI() throws Exception {
+
+ testSendPar();
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(REQUEST_URI,
+ "urn:ietf:params:oauth:par:request_uri:invalid_request_uri"));
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, consumerKey));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.AUTHORIZE_ENDPOINT_URL, urlParameters);
+ String locationHeader = response.getFirstHeader("Location") != null ?
+ response.getFirstHeader("Location").getValue() : null;
+
+ Assert.assertNotNull(locationHeader, "Location header from the authz response is null");
+ Assert.assertTrue(StringUtils.contains(locationHeader, "oauthErrorMsg=par.invalid.request.uri"));
+ }
+
+ @Test(groups = "wso2.is", description = "Send authorize user request with expired request uri",
+ dependsOnMethods = "testSendAuthorizeWithInvalidRequestURI")
+ public void testSendAuthorizeWithExpiredRequestURI() throws Exception {
+
+ testSendPar();
+ // Sleep for 1 min for request uri timeout
+ Thread.sleep(60 * 1000);
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(REQUEST_URI, requestUri));
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, consumerKey));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.AUTHORIZE_ENDPOINT_URL, urlParameters);
+ String locationHeader = response.getFirstHeader("Location") != null ?
+ response.getFirstHeader("Location").getValue() : null;
+
+ Assert.assertNotNull(locationHeader, "Location header from the authz response is null");
+ Assert.assertTrue(StringUtils.contains(locationHeader, "oauthErrorMsg=par.request.uri.expired"));
+ }
+
+ @Test(groups = "wso2.is", description = "Send PAR with repeated param",
+ dependsOnMethods = "testSendAuthorizeWithExpiredRequestURI")
+ public void testSendParWithRepeatedParam() throws Exception {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, consumerKey));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, OAuth2Constant.CALLBACK_URL));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, "repeated_redirect_uri"));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE,
+ OAuth2Constant.OAUTH2_GRANT_TYPE_CODE));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ assertResponse(response, Response.Status.BAD_REQUEST.getStatusCode(),
+ "Invalid request with repeated parameters.", "invalid_request");
+ }
+
+ @Test(groups = "wso2.is", description = "Send PAR with invalid client id",
+ dependsOnMethods = "testSendParWithRepeatedParam")
+ public void testSendParWithInvalidClient() throws Exception {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, "invalid_consumerKey"));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, OAuth2Constant.CALLBACK_URL));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE, OAuth2Constant.OAUTH2_GRANT_TYPE_CODE));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ assertResponse(response, Response.Status.UNAUTHORIZED.getStatusCode(),
+ "A valid OAuth client could not be found for client_id: invalid_consumerKey",
+ "invalid_client");
+ }
+
+ @Test(groups = "wso2.is", description = "Send PAR without client id",
+ dependsOnMethods = "testSendParWithInvalidClient")
+ public void testSendParWithoutClient() throws Exception {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, OAuth2Constant.CALLBACK_URL));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE, OAuth2Constant.OAUTH2_GRANT_TYPE_CODE));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ assertResponse(response, Response.Status.UNAUTHORIZED.getStatusCode(),
+ "Client ID not found in the request.", "invalid_client");
+ }
+
+ @Test(groups = "wso2.is", description = "Send PAR with invalid response type",
+ dependsOnMethods = "testSendParWithoutClient")
+ public void testSendParWithInvalidResponseType() throws Exception {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, consumerKey));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, OAuth2Constant.CALLBACK_URL));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE, "invalid_responseType"));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ assertResponse(response, Response.Status.BAD_REQUEST.getStatusCode(),
+ "Invalid response_type parameter value", "invalid_request");
+ }
+
+ @Test(groups = "wso2.is", description = "Send PAR with invalid redirect uri",
+ dependsOnMethods = "testSendParWithInvalidResponseType")
+ public void testSendParWithInvalidRedirectURI() throws Exception {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, consumerKey));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, "invalid_redirect_URI"));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE, OAuth2Constant.OAUTH2_GRANT_TYPE_CODE));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ assertResponse(response, Response.Status.BAD_REQUEST.getStatusCode(),
+ "callback.not.match", "invalid_request");
+ }
+
+ @Test(groups = "wso2.is", description = "Send PAR with request uri",
+ dependsOnMethods = "testSendParWithInvalidRedirectURI")
+ public void testSendParWithRequestURI() throws Exception {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair(CLIENT_ID_PARAM, consumerKey));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_REDIRECT_URI, OAuth2Constant.CALLBACK_URL));
+ urlParameters.add(new BasicNameValuePair(OAuth2Constant.OAUTH2_RESPONSE_TYPE,
+ OAuth2Constant.OAUTH2_GRANT_TYPE_CODE));
+ urlParameters.add(new BasicNameValuePair(REQUEST_URI,
+ "urn:ietf:params:oauth:par:request_uri:75fb6713-62fa-4d2f-9f72-0e05eab0d331"));
+
+ HttpResponse response = sendPostRequest(OAuth2Constant.PAR_ENDPOINT, urlParameters);
+ assertResponse(response, Response.Status.BAD_REQUEST.getStatusCode(),
+ "Request with request_uri not allowed.", "invalid_request");
}
/**
@@ -211,4 +351,32 @@ private ApplicationResponseModel createApp() throws Exception {
return getApplication(appId);
}
+
+ private HttpResponse sendPostRequest(String endpoint, List parameters) throws Exception {
+
+ HttpPost httpPost = new HttpPost(endpoint);
+ httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
+ httpPost.setEntity(new UrlEncodedFormEntity(parameters));
+ return client.execute(httpPost);
+ }
+
+ private void assertResponse(HttpResponse response, int expectedStatusCode,
+ String expectedErrorDescription, String expectedError) throws Exception {
+
+ int responseCode = response.getStatusLine().getStatusCode();
+ String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
+
+ JSONParser parser = new JSONParser();
+ JSONObject jsonResponse = (JSONObject) parser.parse(responseString);
+ if (jsonResponse == null) {
+ throw new Exception("Error occurred while getting the response.");
+ }
+
+ Assert.assertEquals(responseCode, expectedStatusCode, "Response status code does not match.");
+ Assert.assertEquals(jsonResponse.get("error_description").toString(), expectedErrorDescription,
+ "Error description is missing or invalid value");
+ Assert.assertEquals(jsonResponse.get("error").toString(), expectedError,
+ "Error is missing or invalid value");
+ }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OIDCDiscoveryTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OIDCDiscoveryTestCase.java
index b41f4e769d4..84a178f8beb 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OIDCDiscoveryTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OIDCDiscoveryTestCase.java
@@ -18,7 +18,10 @@
package org.wso2.identity.integration.test.oauth2;
-import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
import org.apache.wink.client.ClientConfig;
import org.apache.wink.client.Resource;
import org.apache.wink.client.RestClient;
@@ -30,39 +33,37 @@
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.charon.core.schema.SCIMConstants;
import org.wso2.identity.integration.common.utils.ISIntegrationTest;
import java.io.IOException;
+import static org.testng.Assert.assertEquals;
+
public class OIDCDiscoveryTestCase extends ISIntegrationTest {
public static final String WEBFINGER_ENDPOINT_SUFFIX = "/.well-known/webfinger";
public static final String RESOURCE = "resource";
public static final String REL = "rel";
private String isServerBackendUrl;
- private String webfingerEndpoint;
- private String relUri = "http://openid.net/specs/connect/1.0/issuer";
- private String discoveryBasePath;
- private DiscoveryConfig config;
-
- @Factory(dataProvider = "webfingerConfigProvider")
- public OIDCDiscoveryTestCase(DiscoveryConfig config) {
- if (log.isDebugEnabled()){
- log.info("SAML SSO Test initialized for " + config);
- }
- this.config = config;
- }
+ private static final String[] expectedResponseModes = {"fragment", "jwt", "fragment.jwt", "query", "form_post",
+ "query.jwt", "form_post.jwt"};
+ private static final String[] expectedAuthModes = {"private_key_jwt", "client_secret_post", "tls_client_auth",
+ "client_secret_basic"};
+ private static final String[] expectedResponseTypes = {"id_token token", "code", "code id_token token",
+ "code id_token", "id_token", "code token", "none", "device", "subject_token", "id_token subject_token",
+ "token"};
+ private static final String[] expectedGrantTypes = {"refresh_token", "password", "client_credentials", "iwa:ntlm",
+ "urn:ietf:params:oauth:grant-type:saml2-bearer", "urn:ietf:params:oauth:grant-type:device_code",
+ "authorization_code", "account_switch", "urn:ietf:params:oauth:grant-type:token-exchange",
+ "organization_switch", "urn:ietf:params:oauth:grant-type:jwt-bearer"};
@BeforeClass(alwaysRun = true)
public void testInit() throws Exception {
super.init();
isServerBackendUrl = isServer.getContextUrls().getWebAppURLHttps();
- webfingerEndpoint = isServerBackendUrl + WEBFINGER_ENDPOINT_SUFFIX + "?" + RESOURCE + "=" + config
- .getResource() + "&" + REL + "=" + relUri;
}
@AfterClass(alwaysRun = true)
@@ -70,9 +71,13 @@ public void atEnd() {
}
- @Test(alwaysRun = true, groups = "wso2.is", description = "webfinger test")
- public void testWebFinger() throws IOException {
+ @Test(alwaysRun = true, groups = "wso2.is", description = "webfinger test",
+ dataProvider = "webFingerConfigProvider")
+ public void testWebFinger(DiscoveryConfig config) {
+ String relUri = "http://openid.net/specs/connect/1.0/issuer";
+ String webFingerEndpoint = isServerBackendUrl + WEBFINGER_ENDPOINT_SUFFIX + "?" + RESOURCE + "=" + config
+ .getResource() + "&" + REL + "=" + relUri;
ClientConfig clientConfig = new ClientConfig();
BasicAuthSecurityHandler basicAuth = new BasicAuthSecurityHandler();
basicAuth.setUserName(userInfo.getUserName());
@@ -80,7 +85,7 @@ public void testWebFinger() throws IOException {
clientConfig.handlers(basicAuth);
RestClient restClient = new RestClient(clientConfig);
- Resource userResource = restClient.resource(webfingerEndpoint);
+ Resource userResource = restClient.resource(webFingerEndpoint);
String response = userResource.accept(SCIMConstants.APPLICATION_JSON).get(String.class);
Object obj= JSONValue.parse(response);
Object links = ((JSONObject)obj).get("links");
@@ -90,8 +95,9 @@ public void testWebFinger() throws IOException {
Assert.assertEquals(openIdProviderIssuerLocation, urlExpected);
}
- @Test(alwaysRun = true, groups = "wso2.is", description = "Discovery test", dependsOnMethods = { "testWebFinger" })
- public void testDiscovery() throws IOException {
+ @Test(alwaysRun = true, groups = "wso2.is", description = "Discovery test", dependsOnMethods = { "testWebFinger" },
+ dataProvider = "oidcDiscoveryConfigProvider")
+ public void testDiscovery(String tenantDomain, String issuer) {
ClientConfig clientConfig = new ClientConfig();
BasicAuthSecurityHandler basicAuth = new BasicAuthSecurityHandler();
@@ -100,21 +106,47 @@ public void testDiscovery() throws IOException {
clientConfig.handlers(basicAuth);
RestClient restClient = new RestClient(clientConfig);
- String discoveryUrl = isServerBackendUrl + "/oauth2/oidcdiscovery/.well-known/openid-configuration";
+ String discoveryUrl = getTenantQualifiedURL(isServerBackendUrl +
+ "/oauth2/" + issuer + "/.well-known/openid-configuration", tenantDomain);
+
Resource userResource = restClient.resource(discoveryUrl);
String response = userResource.accept(SCIMConstants.APPLICATION_JSON).get(String.class);
- Object obj= JSONValue.parse(response);
- String authorization_endpoint = ((JSONObject)obj).get("authorization_endpoint").toString();
- Assert.assertEquals(authorization_endpoint, isServerBackendUrl + "/oauth2/authorize");
- String token_endpoint = ((JSONObject)obj).get("token_endpoint").toString();
- Assert.assertEquals(token_endpoint, isServerBackendUrl + "/oauth2/token");
- String userinfo_endpoint = ((JSONObject)obj).get("userinfo_endpoint").toString();
- Assert.assertEquals(userinfo_endpoint, isServerBackendUrl + "/oauth2/userinfo");
+ JSONObject jsonResponse = (JSONObject) JSONValue.parse(response);
+
+ // Extract and validate the endpoints
+ validateEndpoint(jsonResponse, "authorization_endpoint", "/oauth2/authorize", tenantDomain);
+ validateEndpoint(jsonResponse, "token_endpoint", "/oauth2/token", tenantDomain);
+ validateEndpoint(jsonResponse, "userinfo_endpoint", "/oauth2/userinfo", tenantDomain);
+ validateEndpoint(jsonResponse, "pushed_authorization_request_endpoint", "/oauth2/par", tenantDomain);
+ validateEndpoint(jsonResponse, "introspection_endpoint", "/oauth2/introspect", tenantDomain);
+ validateEndpoint(jsonResponse, "device_authorization_endpoint", "/oauth2/device_authorize", tenantDomain);
+ validateEndpoint(jsonResponse, "end_session_endpoint", "/oidc/logout", tenantDomain);
+ validateEndpoint(jsonResponse, "revocation_endpoint", "/oauth2/revoke", tenantDomain);
+ validateEndpoint(jsonResponse, "jwks_uri", "/oauth2/jwks", tenantDomain);
+ validateEndpoint(jsonResponse, "registration_endpoint",
+ "/api/identity/oauth2/dcr/v1.1/register", tenantDomain);
+ validateArrayElements(jsonResponse, "response_modes_supported", expectedResponseModes);
+ validateArrayElements(jsonResponse, "token_endpoint_auth_methods_supported", expectedAuthModes);
+ validateArrayElements(jsonResponse, "response_types_supported", expectedResponseTypes);
+ validateArrayElements(jsonResponse, "grant_types_supported", expectedGrantTypes);
+ }
+
+ @DataProvider(name = "oidcDiscoveryConfigProvider")
+ public static Object[][] configProvider() {
+
+ return new Object[][]{
+ {"", "oidcdiscovery"},
+ {"carbon.super", "oidcdiscovery"},
+ {"wso2.com", "oidcdiscovery"},
+ {"", "token"},
+ {"carbon.super", "token"},
+ {"wso2.com", "token"},
+ };
}
+ @DataProvider(name = "webFingerConfigProvider")
+ public static Object[][] webFingerConfigProvider(){
- @DataProvider(name = "webfingerConfigProvider")
- public static Object[][] webfingerConfigProvider(){
return new DiscoveryConfig[][]{
{new DiscoveryConfig("acct:admin@localhost", "")},
{new DiscoveryConfig("acct:admin%40wso2.com@localhost", "wso2.com")},
@@ -149,4 +181,63 @@ public void setTenant(String tenant) {
}
}
+ /**
+ * Validates the specific endpoint from the OIDC discovery response.
+ *
+ * @param jsonResponse The parsed JSON object from the response.
+ * @param endpointKey The key of the endpoint in the JSON response.
+ * @param expectedEndpoint The expected suffix for the endpoint URL.
+ * @param tenantDomain Tenant domain intend for testing.
+ */
+ private void validateEndpoint(JSONObject jsonResponse, String endpointKey, String expectedEndpoint,
+ String tenantDomain) {
+
+ String endpointUrl = jsonResponse.get(endpointKey).toString();
+ String expectedUrl = getTenantQualifiedURL(isServerBackendUrl + expectedEndpoint, tenantDomain);
+ Assert.assertEquals(endpointUrl, expectedUrl,
+ String.format("Expected %s to be %s, but found %s", endpointKey, expectedUrl, endpointUrl));
+ }
+
+ private void validateArrayElements(JSONObject jsonResponse, String key, String[] expectedElements) {
+
+ JSONArray elementsArray = (JSONArray) jsonResponse.get(key);
+ String[] actualElements = new String[elementsArray.size()];
+ for (int i = 0; i < elementsArray.size(); i++) {
+ actualElements[i] = (String) elementsArray.get(i);
+ }
+
+ Assert.assertTrue(containsAll(actualElements, expectedElements),
+ String.format("Expected elements to include %s, but found %s",
+ String.join(", ", expectedElements),
+ String.join(", ", actualElements)));
+ }
+
+ private boolean containsAll(String[] actualElements, String[] expectedElements) {
+
+ for (String expectedElement : expectedElements) {
+ boolean found = false;
+ for (String actualElement : actualElements) {
+ if (actualElement.equals(expectedElement)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Test(alwaysRun = true, groups = "wso2.is", description = "Discovery test", dependsOnMethods = { "testDiscovery" })
+ public void testDiscoveryForInvalidIssuer() throws IOException {
+
+ try (CloseableHttpClient client = HttpClients.createDefault()) {
+ String discoveryUrl = isServerBackendUrl + "/oauth2/invalidIssuer/.well-known/openid-configuration";
+ HttpGet request = new HttpGet(discoveryUrl);
+ HttpResponse response = client.execute(request);
+ assertEquals(response.getStatusLine().getStatusCode(), 400, "Expected a Bad Request " +
+ "(HTTP 400) response");
+ }
+ }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAuthCodeGrantOpenIdTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OpenIdUserInfoTestCase.java
similarity index 70%
rename from modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAuthCodeGrantOpenIdTestCase.java
rename to modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OpenIdUserInfoTestCase.java
index 8a0b4ebbde2..b55747360b8 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAuthCodeGrantOpenIdTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OpenIdUserInfoTestCase.java
@@ -25,7 +25,9 @@
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Lookup;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.cookie.CookieSpecProvider;
@@ -33,10 +35,12 @@
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
+import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
+import org.json.simple.parser.JSONParser;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -48,9 +52,6 @@
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationResponseModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
import org.wso2.identity.integration.test.rest.api.user.common.model.Email;
-import org.wso2.identity.integration.test.rest.api.user.common.model.ListObject;
-import org.wso2.identity.integration.test.rest.api.user.common.model.PatchOperationRequestObject;
-import org.wso2.identity.integration.test.rest.api.user.common.model.RoleItemAddGroupobj;
import org.wso2.identity.integration.test.rest.api.user.common.model.UserObject;
import org.wso2.identity.integration.test.restclients.SCIM2RestClient;
import org.wso2.identity.integration.test.utils.DataExtractUtil;
@@ -60,33 +61,30 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import static org.testng.Assert.assertNotNull;
import static org.wso2.identity.integration.test.utils.DataExtractUtil.KeyValue;
+import static org.wso2.identity.integration.test.utils.OAuth2Constant.ACCESS_TOKEN_ENDPOINT;
+import static org.wso2.identity.integration.test.utils.OAuth2Constant.AUTHORIZATION_HEADER;
import static org.wso2.identity.integration.test.utils.OAuth2Constant.COMMON_AUTH_URL;
-public class OAuth2ServiceAuthCodeGrantOpenIdTestCase extends OAuth2ServiceAbstractIntegrationTest {
+public class OpenIdUserInfoTestCase extends OAuth2ServiceAbstractIntegrationTest {
private String accessToken;
private String sessionDataKeyConsent;
private String sessionDataKey;
private String authorizationCode;
AutomationContext context;
-
private String consumerKey;
private String consumerSecret;
-
- private Lookup cookieSpecRegistry;
- private RequestConfig requestConfig;
private CloseableHttpClient client;
-
- private static final String USERS_PATH = "users";
private static final String USER_EMAIL = "abc@wso2.com";
private static final String USERNAME = "authcodegrantuser";
private static final String PASSWORD = "Pass@123";
-
private final List consentParameters = new ArrayList<>();
private final CookieStore cookieStore = new BasicCookieStore();
private final String username;
@@ -102,7 +100,7 @@ public static Object[][] configProvider() {
}
@Factory(dataProvider = "configProvider")
- public OAuth2ServiceAuthCodeGrantOpenIdTestCase(TestUserMode userMode) throws Exception {
+ public OpenIdUserInfoTestCase(TestUserMode userMode) throws Exception {
super.init(userMode);
context = new AutomationContext("IDENTITY", userMode);
@@ -116,10 +114,10 @@ public void testInit() throws Exception {
tenantInfo = context.getContextTenant();
scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo);
- cookieSpecRegistry = RegistryBuilder.create()
+ Lookup cookieSpecRegistry = RegistryBuilder.create()
.register(CookieSpecs.DEFAULT, new RFC6265CookieSpecProvider())
.build();
- requestConfig = RequestConfig.custom()
+ RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.build();
client = HttpClientBuilder.create()
@@ -336,6 +334,120 @@ public void testValidateTokenScope() throws Exception {
Assert.assertTrue(scopes.contains("openid"), "Invalid JWT Token scope Value");
}
+ @Test(groups = "wso2.is", description = "request user info using POST", dependsOnMethods = "testValidateTokenScope")
+ public void testUserInfoPostRequest() throws Exception {
+
+ String userInfoUrl = tenantInfo.getDomain().equalsIgnoreCase("carbon.super") ?
+ OAuth2Constant.USER_INFO_ENDPOINT : OAuth2Constant.TENANT_USER_INFO_ENDPOINT;
+ HttpPost request = new HttpPost(userInfoUrl);
+
+ List urlParameters = Collections.singletonList(
+ new BasicNameValuePair("access_token", accessToken)
+ );
+ request.setHeader("User-Agent", OAuth2Constant.USER_AGENT);
+ request.setHeader("Content-Type", "application/x-www-form-urlencoded");
+ request.setEntity(new UrlEncodedFormEntity(urlParameters));
+
+ HttpResponse response = client.execute(request);
+
+ String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
+ JSONParser parser = new JSONParser();
+ JSONObject jsonResponse = (JSONObject) parser.parse(responseString);
+ if (jsonResponse == null) {
+ throw new Exception("Error occurred while getting the response.");
+ }
+ Assert.assertNotNull(jsonResponse.get("sub"), "sub from introspection endpoint response is null.");
+ Assert.assertNotNull(jsonResponse.get("email"), "sub from introspection endpoint response is null.");
+ }
+
+ @Test(groups = "wso2.is", description = "request user info using POST with invalid token",
+ dependsOnMethods = "testUserInfoPostRequest")
+ public void testUserInfoPostWithInvalidToken() throws Exception {
+
+ String userInfoUrl = tenantInfo.getDomain().equalsIgnoreCase("carbon.super") ?
+ OAuth2Constant.USER_INFO_ENDPOINT : OAuth2Constant.TENANT_USER_INFO_ENDPOINT;
+ HttpPost request = new HttpPost(userInfoUrl);
+
+ List urlParameters = Collections.singletonList(
+ new BasicNameValuePair("access_token", "invalid_access_token")
+ );
+ request.setHeader("User-Agent", OAuth2Constant.USER_AGENT);
+ request.setHeader("Content-Type", "application/x-www-form-urlencoded");
+ request.setEntity(new UrlEncodedFormEntity(urlParameters));
+
+ HttpResponse response = client.execute(request);
+
+ String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
+ JSONParser parser = new JSONParser();
+ JSONObject jsonResponse = (JSONObject) parser.parse(responseString);
+ if (jsonResponse == null) {
+ throw new Exception("Error occurred while getting the response.");
+ }
+ Assert.assertEquals(jsonResponse.get("error_description"),
+ "Access token validation failed", "Unexpected error description");
+ Assert.assertEquals(jsonResponse.get("error"), "invalid_token",
+ "Unexpected error message");
+ }
+
+ @Test(groups = "wso2.is", description = "Send user info request using m2m token",
+ dependsOnMethods = "testUserInfoPostWithInvalidToken")
+ public void testSendAuthorizedPostWithM2MToken() throws Exception {
+
+ List urlParameters = new ArrayList<>();
+ urlParameters.add(new BasicNameValuePair("grant_type",
+ OAuth2Constant.OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS));
+ urlParameters.add(new BasicNameValuePair("scope", OAuth2Constant.OAUTH2_SCOPE_OPENID+ " "
+ + OAuth2Constant.OAUTH2_SCOPE_EMAIL));
+
+ List headers = new ArrayList<>();
+ headers.add(new BasicHeader(AUTHORIZATION_HEADER, OAuth2Constant.BASIC_HEADER + " " +
+ getBase64EncodedString(consumerKey, consumerSecret)));
+ headers.add(new BasicHeader("Content-Type", "application/x-www-form-urlencoded"));
+ headers.add(new BasicHeader("User-Agent", OAuth2Constant.USER_AGENT));
+
+ HttpResponse response = sendPostRequest(client, headers, urlParameters,
+ getTenantQualifiedURL(ACCESS_TOKEN_ENDPOINT, tenantInfo.getDomain()));
+
+ Assert.assertNotNull(response, "Authorization request failed. Authorized response is null");
+
+ String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
+ JSONParser parser = new JSONParser();
+ JSONObject jsonResponse = (JSONObject) parser.parse(responseString);
+ if (jsonResponse == null) {
+ throw new Exception("Error occurred while getting the m2m token response.");
+ }
+ String m2mAccessToken = (String) jsonResponse.get("access_token");
+ assertNotNull(m2mAccessToken, "M2M Access token is null.");
+
+ String userInfoUrl = tenantInfo.getDomain().equalsIgnoreCase("carbon.super") ?
+ OAuth2Constant.USER_INFO_ENDPOINT : OAuth2Constant.TENANT_USER_INFO_ENDPOINT;
+ HttpPost request = new HttpPost(userInfoUrl);
+
+ urlParameters = Collections.singletonList(
+ new BasicNameValuePair("access_token", m2mAccessToken)
+ );
+ request.setHeader("User-Agent", OAuth2Constant.USER_AGENT);
+ request.setHeader("Content-Type", "application/x-www-form-urlencoded");
+ request.setEntity(new UrlEncodedFormEntity(urlParameters));
+
+ response = client.execute(request);
+
+ responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+ EntityUtils.consume(response.getEntity());
+ jsonResponse = (JSONObject) parser.parse(responseString);
+ if (jsonResponse == null) {
+ throw new Exception("Error occurred while getting the response.");
+ }
+ Assert.assertEquals(jsonResponse.get("error_description"),
+ "Access token does not have the openid scope", "Unexpected error description");
+ Assert.assertEquals(jsonResponse.get("error"), "insufficient_scope",
+ "Unexpected error message");
+ }
+
+
public HttpResponse sendLoginPost(HttpClient client, String sessionDataKey) throws IOException {
List urlParameters = new ArrayList<>();
@@ -361,15 +473,6 @@ private void addAdminUser() throws Exception {
userInfo.setUserName(USERNAME);
userInfo.setPassword(PASSWORD);
userInfo.addEmail(new Email().value(USER_EMAIL));
-
userId = scim2RestClient.createUser(userInfo);
- String roleId = scim2RestClient.getRoleIdByName("admin");
-
- RoleItemAddGroupobj patchRoleItem = new RoleItemAddGroupobj();
- patchRoleItem.setOp(RoleItemAddGroupobj.OpEnum.ADD);
- patchRoleItem.setPath(USERS_PATH);
- patchRoleItem.addValue(new ListObject().value(userId));
-
- scim2RestClient.updateUserRole(new PatchOperationRequestObject().addOperations(patchRoleItem), roleId);
}
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCIdentityFederationTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCIdentityFederationTestCase.java
index 9a9ead40a1e..f2663b12a42 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCIdentityFederationTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCIdentityFederationTestCase.java
@@ -18,7 +18,6 @@
package org.wso2.identity.integration.test.oidc;
-import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
@@ -37,7 +36,6 @@
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.util.EntityUtils;
import org.opensaml.xml.util.Base64;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
@@ -48,13 +46,13 @@
import org.wso2.carbon.automation.engine.context.AutomationContext;
import org.wso2.carbon.automation.engine.context.TestUserMode;
import org.wso2.identity.integration.test.application.mgt.AbstractIdentityFederationTestCase;
+import org.wso2.identity.integration.test.base.MockOIDCIdentityProvider;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationResponseModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AuthenticationSequence;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AuthenticationSequence.TypeEnum;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.Authenticator;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.InboundProtocols;
-import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.SAML2Configuration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.SAML2ServiceProvider;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.SAMLAssertionConfiguration;
@@ -67,13 +65,6 @@
import org.wso2.identity.integration.test.rest.api.server.idp.v1.model.IdentityProviderPOSTRequest;
import org.wso2.identity.integration.test.rest.api.server.idp.v1.model.ProvisioningRequest;
import org.wso2.identity.integration.test.rest.api.server.idp.v1.model.ProvisioningRequest.JustInTimeProvisioning;
-import org.wso2.identity.integration.test.rest.api.user.common.model.ListObject;
-import org.wso2.identity.integration.test.rest.api.user.common.model.PatchOperationRequestObject;
-import org.wso2.identity.integration.test.rest.api.user.common.model.RoleItemAddGroupobj;
-import org.wso2.identity.integration.test.rest.api.user.common.model.UserObject;
-import org.wso2.identity.integration.test.restclients.SCIM2RestClient;
-import org.wso2.identity.integration.test.util.Utils;
-import org.wso2.identity.integration.test.utils.DataExtractUtil;
import org.wso2.identity.integration.test.utils.IdentityConstants;
import org.wso2.identity.integration.test.utils.OAuth2Constant;
@@ -81,10 +72,13 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
+
+import static org.wso2.identity.integration.test.base.MockOIDCIdentityProvider.MOCK_IDP_AUTHORIZE_ENDPOINT;
+import static org.wso2.identity.integration.test.base.MockOIDCIdentityProvider.MOCK_IDP_CLIENT_ID;
+import static org.wso2.identity.integration.test.base.MockOIDCIdentityProvider.MOCK_IDP_CLIENT_SECRET;
+import static org.wso2.identity.integration.test.base.MockOIDCIdentityProvider.MOCK_IDP_LOGOUT_ENDPOINT;
+import static org.wso2.identity.integration.test.base.MockOIDCIdentityProvider.MOCK_IDP_TOKEN_ENDPOINT;
/**
* Integration test cases for SAML-OIDC federation scenarios.
@@ -108,34 +102,15 @@ public class OIDCIdentityFederationTestCase extends AbstractIdentityFederationTe
private static final String ENCODED_PRIMARY_IS_IDP_AUTHENTICATOR_ID_OIDC = "T3BlbklEQ29ubmVjdEF1dGhlbnRpY2F0b3I";
private static final String PRIMARY_IS_IDP_CALLBACK_URL = "https://localhost:9853/commonauth";
- private static final String SECONDARY_IS_TEST_USERNAME = "testFederatedUser";
- private static final String SECONDARY_IS_TEST_PASSWORD = "TestFederatePassword@123";
- private static final String SECONDARY_IS_TEST_USER_ROLES = "admin";
-
- private static final String SECONDARY_IS_SP_NAME = "secondarySP";
- private static final String SECONDARY_IS_IDP_CALLBACK_URL = "https://localhost:9854/commonauth";
- private static final String SECONDARY_IS_TOKEN_ENDPOINT = "https://localhost:9854/oauth2/token";
- private static final String SECONDARY_IS_LOGOUT_ENDPOINT = "https://localhost:9854/oidc/logout";
- private static final String SECONDARY_IS_AUTHORIZE_ENDPOINT = "https://localhost:9854/oauth2/authorize";
- private static final String HTTPS_LOCALHOST_SERVICES = "https://localhost:%s/";
- private String secondaryISClientID;
- private String secondaryISClientSecret;
- private final String username;
- private final String userPassword;
private final AutomationContext context;
private static final int PORT_OFFSET_0 = 0;
- private static final int PORT_OFFSET_1 = 1;
CookieStore cookieStore;
- private Lookup cookieSpecRegistry;
- private RequestConfig requestConfig;
private CloseableHttpClient client;
- private String secondaryISAppId;
private String primaryISIdpId;
private String primaryISAppId;
- private SCIM2RestClient scim2RestClient;
- private String secondaryISUserId;
+ private MockOIDCIdentityProvider mockIdP;
@DataProvider(name = "configProvider")
public static Object[][] configProvider() {
@@ -146,31 +121,27 @@ public static Object[][] configProvider() {
public OIDCIdentityFederationTestCase(TestUserMode userMode) throws Exception {
context = new AutomationContext("IDENTITY", userMode);
- this.username = context.getContextTenant().getTenantAdmin().getUserName();
- this.userPassword = context.getContextTenant().getTenantAdmin().getPassword();
}
@BeforeClass(alwaysRun = true)
public void initTest() throws Exception {
+ mockIdP = new MockOIDCIdentityProvider();
+ mockIdP.start();
super.initTest();
createServiceClients(PORT_OFFSET_0, new IdentityConstants.ServiceClientType[]{
IdentityConstants.ServiceClientType.APPLICATION_MANAGEMENT,
IdentityConstants.ServiceClientType.IDENTITY_PROVIDER_MGT});
- createServiceClients(PORT_OFFSET_1, new IdentityConstants.ServiceClientType[]{
- IdentityConstants.ServiceClientType.APPLICATION_MANAGEMENT});
-
- createApplicationInSecondaryIS();
createIDPInPrimaryIS();
createApplicationInPrimaryIS();
cookieStore = new BasicCookieStore();
- cookieSpecRegistry = RegistryBuilder.create()
+ Lookup cookieSpecRegistry = RegistryBuilder.create()
.register(CookieSpecs.DEFAULT, new RFC6265CookieSpecProvider())
.build();
- requestConfig = RequestConfig.custom()
+ RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.build();
client = HttpClientBuilder.create()
@@ -178,9 +149,6 @@ public void initTest() throws Exception {
.setDefaultRequestConfig(requestConfig)
.setDefaultCookieStore(cookieStore)
.build();
-
- scim2RestClient = new SCIM2RestClient(getSecondaryISURI(), tenantInfo);
- addUserToSecondaryIS();
}
@AfterClass(alwaysRun = true)
@@ -189,14 +157,11 @@ public void endTest() throws Exception {
try {
deleteApplication(PORT_OFFSET_0, primaryISAppId);
deleteIdp(PORT_OFFSET_0, primaryISIdpId);
- deleteApplication(PORT_OFFSET_1, secondaryISAppId);
-
- deleteAddedUsersInSecondaryIS();
client.close();
- scim2RestClient.closeHttpClient();
+ mockIdP.stop();
} catch (Exception e) {
- log.error("Failure occured due to :" + e.getMessage(), e);
+ log.error("Failure occurred due to :" + e.getMessage(), e);
throw e;
}
}
@@ -204,17 +169,14 @@ public void endTest() throws Exception {
@Test(groups = "wso2.is", description = "Check SAML-to-OIDC federated login")
public void testFederatedLogin() throws Exception {
- String sessionDataKeyOfSecondaryISLogin = sendSAMLRequestToPrimaryIS();
- Assert.assertNotNull(sessionDataKeyOfSecondaryISLogin,
- "Unable to acquire 'sessionDataKey' value in secondary IS");
-
- String sessionDataKeyConsentOfSecondaryIS = doAuthenticationInSecondaryIS(sessionDataKeyOfSecondaryISLogin);
- Assert.assertNotNull(sessionDataKeyConsentOfSecondaryIS, "Invalid sessionDataKeyConsent.");
-
- String callbackURLOfPrimaryIS = doConsentApprovalInSecondaryIS(sessionDataKeyConsentOfSecondaryIS);
- Assert.assertNotNull(callbackURLOfPrimaryIS, "Unable to acquire authorizeCallbackURL in primary IS");
+ // Sending the SAML request to the primary IS
+ // Client will handle all the redirections and will return the final response of the flow which contains the
+ // SAMLResponse. This is because the mock server is not prompting anything to the user.
+ HttpGet request = new HttpGet(SAML_SSO_URL);
+ request.setHeader("User-Agent", USER_AGENT);
+ HttpResponse response = client.execute(request);
- String samlResponse = getSAMLResponseFromPrimaryIS(callbackURLOfPrimaryIS);
+ String samlResponse = extractValueFromResponse(response, "SAMLResponse", 5);
Assert.assertNotNull(samlResponse, "Unable to acquire SAML response from primary IS");
String decodedSAMLResponse = new String(Base64.decode(samlResponse));
@@ -224,15 +186,17 @@ public void testFederatedLogin() throws Exception {
String homepageContent = sendSAMLResponseToWebApp(samlResponse);
boolean isValidLogin = validateLoginHomePageContent(homepageContent);
Assert.assertTrue(isValidLogin, "Invalid SAML login response received by travelocity app");
+ mockIdP.verifyForAuthzCodeFlow();
}
@Test(groups = "wso2.is", description = "Check SAML-to-OIDC federated logout", dependsOnMethods = {
"testFederatedLogin"})
public void testLogout() throws Exception {
- sendLogoutRequestToPrimaryIS();
+ HttpResponse response = sendGetRequest(client, SAML_LOGOUT_URL);
+ Assert.assertNotNull(response);
- String samlLogoutResponseToWebapp = doLogoutConsentApprovalInSecondaryIS();
+ String samlLogoutResponseToWebapp = extractValueFromResponse(response, "SAMLResponse", 5);
Assert.assertNotNull(samlLogoutResponseToWebapp,
"Unable to acquire SAML Logout response from travelocity app");
@@ -242,6 +206,7 @@ public void testLogout() throws Exception {
String logoutPageContent = sendSAMLResponseToWebApp(samlLogoutResponseToWebapp);
boolean isValidLogout = validateLogoutPageContent(logoutPageContent);
Assert.assertTrue(isValidLogout, "Invalid SAML Logout response received by travelocity app");
+ mockIdP.verifyForLogoutFlow();
}
/**TODO Test case for consent denial from the federated IdP during the logout. Implement after resolving
@@ -259,34 +224,6 @@ public void testLogout() throws Exception {
// Assert.assertTrue(consentDeniedResponseToWebapp.contains("access_denied"));
// }
- private void addUserToSecondaryIS() throws Exception {
-
- UserObject user = new UserObject()
- .userName(SECONDARY_IS_TEST_USERNAME)
- .password(SECONDARY_IS_TEST_PASSWORD);
-
- secondaryISUserId = scim2RestClient.createUser(user);
- Assert.assertNotNull(secondaryISUserId, "User creation failed in secondary IS.");
-
- RoleItemAddGroupobj rolePatchReqObject = new RoleItemAddGroupobj();
- rolePatchReqObject.setOp(RoleItemAddGroupobj.OpEnum.ADD);
- rolePatchReqObject.setPath("users");
- rolePatchReqObject.addValue(new ListObject().value(secondaryISUserId));
-
- String adminRoleId = scim2RestClient.getRoleIdByName(SECONDARY_IS_TEST_USER_ROLES);
- scim2RestClient.updateUserRole(new PatchOperationRequestObject().addOperations(rolePatchReqObject), adminRoleId);
- }
-
- private void deleteAddedUsersInSecondaryIS() throws IOException {
-
- scim2RestClient.deleteUser(secondaryISUserId);
- }
-
- protected String getSecondaryISURI() {
-
- return String.format(HTTPS_LOCALHOST_SERVICES, DEFAULT_PORT + PORT_OFFSET_1);
- }
-
private void createApplicationInPrimaryIS() throws Exception {
ApplicationModel applicationCreationModel = new ApplicationModel()
@@ -313,26 +250,6 @@ private void createApplicationInPrimaryIS() throws Exception {
"Failed to update local and outbound configs in primary IS");
}
- private void createApplicationInSecondaryIS() throws Exception {
-
- ApplicationModel applicationCreationModel = new ApplicationModel()
- .name(SECONDARY_IS_SP_NAME)
- .description("This is a test Service Provider")
- .isManagementApp(true)
- .inboundProtocolConfiguration(new InboundProtocols().oidc(getOIDCConfigurations()));
-
- secondaryISAppId = addApplication(PORT_OFFSET_1, applicationCreationModel);
- Assert.assertNotNull(secondaryISAppId, "Failed to create service provider 'secondarySP' in secondary IS");
-
- OpenIDConnectConfiguration oidcConfig = getOIDCInboundDetailsOfApplication(PORT_OFFSET_1, secondaryISAppId);
- secondaryISClientID = oidcConfig.getClientId();
- Assert.assertNotNull(secondaryISClientID,
- "Failed to update service provider with inbound OIDC configs in secondary IS");
- secondaryISClientSecret = oidcConfig.getClientSecret();
- Assert.assertNotNull(secondaryISClientSecret,
- "Failed to update service provider with inbound OIDC configs in secondary IS");
- }
-
private void createIDPInPrimaryIS() throws Exception {
FederatedAuthenticator authenticator = new FederatedAuthenticator()
@@ -344,22 +261,22 @@ private void createIDPInPrimaryIS() throws Exception {
.value("oidcFedIdP"))
.addProperty(new org.wso2.identity.integration.test.rest.api.server.idp.v1.model.Property()
.key(IdentityConstants.Authenticator.OIDC.CLIENT_ID)
- .value(secondaryISClientID))
+ .value(MOCK_IDP_CLIENT_ID))
.addProperty(new org.wso2.identity.integration.test.rest.api.server.idp.v1.model.Property()
.key(IdentityConstants.Authenticator.OIDC.CLIENT_SECRET)
- .value(secondaryISClientSecret))
+ .value(MOCK_IDP_CLIENT_SECRET))
.addProperty(new org.wso2.identity.integration.test.rest.api.server.idp.v1.model.Property()
.key(IdentityConstants.Authenticator.OIDC.OAUTH2_AUTHZ_URL)
- .value(SECONDARY_IS_AUTHORIZE_ENDPOINT))
+ .value(MOCK_IDP_AUTHORIZE_ENDPOINT))
.addProperty(new org.wso2.identity.integration.test.rest.api.server.idp.v1.model.Property()
.key(IdentityConstants.Authenticator.OIDC.OAUTH2_TOKEN_URL)
- .value(SECONDARY_IS_TOKEN_ENDPOINT))
+ .value(MOCK_IDP_TOKEN_ENDPOINT))
.addProperty(new org.wso2.identity.integration.test.rest.api.server.idp.v1.model.Property()
.key(IdentityConstants.Authenticator.OIDC.CALLBACK_URL)
.value(PRIMARY_IS_IDP_CALLBACK_URL))
.addProperty(new org.wso2.identity.integration.test.rest.api.server.idp.v1.model.Property()
.key(IdentityConstants.Authenticator.OIDC.OIDC_LOGOUT_URL)
- .value(SECONDARY_IS_LOGOUT_ENDPOINT))
+ .value(MOCK_IDP_LOGOUT_ENDPOINT))
.addProperty(new org.wso2.identity.integration.test.rest.api.server.idp.v1.model.Property()
.key("commonAuthQueryParams")
.value("scope=" + OAuth2Constant.OAUTH2_SCOPE_OPENID_WITH_INTERNAL_LOGIN));
@@ -382,19 +299,6 @@ private void createIDPInPrimaryIS() throws Exception {
Assert.assertNotNull(primaryISIdpId, "Failed to create Identity Provider 'trustedIdP' in primary IS");
}
- private OpenIDConnectConfiguration getOIDCConfigurations() {
-
- List grantTypes = new ArrayList<>();
- Collections.addAll(grantTypes, "authorization_code", "implicit", "password", "client_credentials",
- "refresh_token", "urn:ietf:params:oauth:grant-type:saml2-bearer", "iwa:ntlm");
-
- OpenIDConnectConfiguration oidcConfig = new OpenIDConnectConfiguration();
- oidcConfig.setGrantTypes(grantTypes);
- oidcConfig.addCallbackURLsItem(PRIMARY_IS_IDP_CALLBACK_URL);
-
- return oidcConfig;
- }
-
private SAML2Configuration getSAMLConfigurations() {
SAML2ServiceProvider serviceProvider = new SAML2ServiceProvider()
@@ -415,127 +319,6 @@ private SAML2Configuration getSAMLConfigurations() {
return new SAML2Configuration().manualConfiguration(serviceProvider);
}
- private String sendSAMLRequestToPrimaryIS() throws Exception {
-
- HttpGet request = new HttpGet(SAML_SSO_URL);
- request.setHeader("User-Agent", USER_AGENT);
- HttpResponse response = client.execute(request);
- return extractValueFromResponse(response, "name=\"sessionDataKey\"", 1);
- }
-
- private String doAuthenticationInSecondaryIS(String sessionDataKey) throws Exception {
-
- HttpResponse response = sendLoginPost(client, sessionDataKey);
- Assert.assertNotNull(response, "Login request failed. response is null.");
-
- Header locationHeader = response.getFirstHeader(OAuth2Constant.HTTP_RESPONSE_HEADER_LOCATION);
- Assert.assertNotNull(locationHeader, "Login response header is null.");
- EntityUtils.consume(response.getEntity());
-
- response = sendGetRequest(client, locationHeader.getValue());
- Map keyPositionMap = new HashMap<>(1);
- keyPositionMap.put("name=\"sessionDataKeyConsent\"", 1);
- List keyValues = DataExtractUtil.extractSessionConsentDataFromResponse(response,
- keyPositionMap);
- Assert.assertNotNull(keyValues, "SessionDataKeyConsent key value is null.");
-
- String sessionDataKeyConsent = keyValues.get(0).getValue();
- EntityUtils.consume(response.getEntity());
-
- return sessionDataKeyConsent;
- }
-
- private HttpResponse sendLoginPost(HttpClient client, String sessionDataKey) throws IOException {
-
- List urlParameters = new ArrayList<>();
- urlParameters.add(new BasicNameValuePair("username", SECONDARY_IS_TEST_USERNAME + "@" + tenantInfo.getDomain()));
- urlParameters.add(new BasicNameValuePair("password", SECONDARY_IS_TEST_PASSWORD));
- urlParameters.add(new BasicNameValuePair("sessionDataKey", sessionDataKey));
-
- HttpResponse response = sendPostRequestWithParameters(client, urlParameters, SECONDARY_IS_IDP_CALLBACK_URL);
-
- return response;
- }
-
- private String doConsentApprovalInSecondaryIS(String sessionDataKeyConsent) throws Exception {
-
- List consentParameters = new ArrayList<>();
-
- HttpResponse response = sendApprovalPostWithConsent(client, sessionDataKeyConsent, consentParameters);
- Assert.assertNotNull(response, "Approval request failed.");
-
- Header locationHeader = response.getFirstHeader(OAuth2Constant.HTTP_RESPONSE_HEADER_LOCATION);
- EntityUtils.consume(response.getEntity());
-
- String authzResponseURL = locationHeader.getValue();
- Assert.assertNotNull(authzResponseURL, "Approval request failed for.");
-
- String authorizeURL = testAuthzCode(authzResponseURL);
- return authorizeURL;
- }
-
- private HttpResponse sendApprovalPostWithConsent(HttpClient client, String sessionDataKeyConsent,
- List consentClaims) throws IOException {
-
- List urlParameters = new ArrayList<>();
- urlParameters.add(new BasicNameValuePair("sessionDataKeyConsent", sessionDataKeyConsent));
- urlParameters.add(new BasicNameValuePair("scope-approval", "approve"));
- urlParameters.add(new BasicNameValuePair("user_claims_consent", "true"));
- urlParameters.add(new BasicNameValuePair("consent_select_all", "on"));
- urlParameters.add(new BasicNameValuePair("consent_0", "on"));
- urlParameters.add(new BasicNameValuePair("consent", "approve"));
-
- if (consentClaims != null) {
- urlParameters.addAll(consentClaims);
- }
-
- HttpResponse response = sendPostRequestWithParameters(client, urlParameters, SECONDARY_IS_AUTHORIZE_ENDPOINT);
- return response;
- }
-
- private String testAuthzCode(String authzResponseURL) throws Exception {
-
- HttpClient httpClientWithoutAutoRedirections = HttpClientBuilder.create()
- .disableRedirectHandling()
- .setDefaultCookieSpecRegistry(cookieSpecRegistry)
- .setDefaultRequestConfig(requestConfig)
- .setDefaultCookieStore(cookieStore).build();
-
- HttpResponse response = sendGetRequest(httpClientWithoutAutoRedirections, authzResponseURL);
- Assert.assertNotNull(response, "Authorization code response to primary IS is invalid.");
-
- String locationHeader = getHeaderValue(response, "Location");
- Assert.assertNotNull(locationHeader, "locationHeader not found in response.");
-
- String pastrCookie = Utils.getPastreCookie(response);
- Assert.assertNotNull(pastrCookie, "pastr cookie not found in response.");
-
- if (Utils.requestMissingClaims(response)) {
- locationHeader = handleMissingClaims(response, locationHeader, client, pastrCookie);
- Assert.assertNotNull(locationHeader, "locationHeader not found in response.");
- }
-
- return locationHeader;
- }
-
- private String handleMissingClaims(HttpResponse response, String locationHeader, HttpClient client, String
- pastrCookie) throws Exception {
-
- EntityUtils.consume(response.getEntity());
-
- response = Utils.sendPOSTConsentMessage(response, PRIMARY_IS_IDP_CALLBACK_URL, USER_AGENT, locationHeader,
- client, pastrCookie);
- EntityUtils.consume(response.getEntity());
-
- return getHeaderValue(response, "Location");
- }
-
- private String getSAMLResponseFromPrimaryIS(String callbackURL) throws IOException {
-
- HttpResponse response = sendGetRequest(client, callbackURL);
- return extractValueFromResponse(response, "SAMLResponse", 5);
- }
-
private String sendSAMLResponseToWebApp(String samlResponse)
throws Exception {
@@ -556,7 +339,7 @@ private HttpResponse getHttpResponseWebApp(String samlResponse) throws IOExcepti
HttpPost request = new HttpPost(PRIMARY_IS_SAML_ACS_URL);
request.setHeader("User-Agent", USER_AGENT);
- List urlParameters = new ArrayList();
+ List urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("SAMLResponse", samlResponse));
request.setEntity(new UrlEncodedFormEntity(urlParameters));
return client.execute(request);
@@ -567,60 +350,11 @@ private boolean validateLoginHomePageContent(String homepageContent) {
return homepageContent.contains("You are logged in as ");
}
- private HttpResponse sendLogoutRequestToPrimaryIS() throws IOException {
-
- HttpResponse response = sendGetRequest(client, SAML_LOGOUT_URL);
- EntityUtils.consume(response.getEntity());
- Assert.assertNotNull(response);
- return response;
- }
-
- private String doLogoutConsentApprovalInSecondaryIS() throws Exception {
-
- HttpResponse response = sendLogoutApprovalPostWithConsent(client);
- Assert.assertNotNull(response, "Approval request failed.");
-
- Header locationHeader = response.getFirstHeader(OAuth2Constant.HTTP_RESPONSE_HEADER_LOCATION);
- Assert.assertNotNull(locationHeader, "Approval request failed for.");
- EntityUtils.consume(response.getEntity());
-
- String logoutResponseToPrimaryIS = locationHeader.getValue();
-
- response = sendGetRequest(client, logoutResponseToPrimaryIS);
- return extractValueFromResponse(response, "SAMLResponse", 5);
- }
-
- private String doLogoutConsentDenyInSecondaryIS() throws Exception {
-
- HttpResponse response = sendLogoutDenyPostWithConsent(client);
- Assert.assertNotNull(response, "Approval request failed.");
-
- Header locationHeader = response.getFirstHeader(OAuth2Constant.HTTP_RESPONSE_HEADER_LOCATION);
- Assert.assertNotNull(locationHeader, "Approval request failed for.");
- EntityUtils.consume(response.getEntity());
-
- String logoutResponseToPrimaryIS = locationHeader.getValue();
-
- response = sendGetRequest(client, logoutResponseToPrimaryIS);
- return extractValueFromResponse(response, "error", 3);
- }
-
private boolean validateLogoutPageContent(String logoutPageContent) {
return logoutPageContent.contains("location.href = \"index.jsp\"");
}
- private HttpResponse sendPostRequestWithParameters(HttpClient client, List urlParameters, String url)
- throws ClientProtocolException, IOException {
-
- HttpPost request = new HttpPost(url);
- request.setHeader("User-Agent", OAuth2Constant.USER_AGENT);
- request.setEntity(new UrlEncodedFormEntity(urlParameters));
-
- HttpResponse response = client.execute(request);
- return response;
- }
-
private HttpResponse sendGetRequest(HttpClient client, String locationURL) throws ClientProtocolException,
IOException {
@@ -630,32 +364,4 @@ private HttpResponse sendGetRequest(HttpClient client, String locationURL) throw
return response;
}
-
- private HttpResponse sendLogoutApprovalPostWithConsent(HttpClient client) throws IOException {
-
- List urlParameters = new ArrayList<>();
- urlParameters.add(new BasicNameValuePair("consent", "approve"));
-
- HttpResponse response = sendPostRequestWithParameters(client, urlParameters, SECONDARY_IS_LOGOUT_ENDPOINT);
- return response;
- }
-
- private HttpResponse sendLogoutDenyPostWithConsent(HttpClient client) throws IOException {
-
- List urlParameters = new ArrayList<>();
- urlParameters.add(new BasicNameValuePair("consent", "deny"));
-
- HttpResponse response = sendPostRequestWithParameters(client, urlParameters, SECONDARY_IS_LOGOUT_ENDPOINT);
- return response;
- }
-
- private HttpResponse sendPostRequest(HttpClient client, String locationURL) throws ClientProtocolException,
- IOException {
-
- HttpPost postRequest = new HttpPost(locationURL);
- postRequest.setHeader("User-Agent", OAuth2Constant.USER_AGENT);
- HttpResponse response = client.execute(postRequest);
-
- return response;
- }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsSuccessTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsSuccessTest.java
index 1e51aa627aa..7e7494bb729 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsSuccessTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsSuccessTest.java
@@ -132,7 +132,7 @@ public void testGetActionByActionType() {
}
@Test(dependsOnMethods = {"testGetActionByActionType"})
- public void testGetActions() {
+ public void testGetActionTypes() {
Response responseOfGet = getResponseOfGet(ACTION_MANAGEMENT_API_BASE_PATH + TYPES_API_PATH);
responseOfGet.then()
@@ -148,7 +148,7 @@ public void testGetActions() {
.body( "find { it.type == '" + PRE_ISSUE_ACCESS_TOKEN_ACTION_TYPE + "' }.self", notNullValue());
}
- @Test(dependsOnMethods = {"testGetActions"})
+ @Test(dependsOnMethods = {"testGetActionTypes"})
public void testUpdateAction() {
// Update all the attributes of the action.
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsTestBase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsTestBase.java
index f68c245a4fb..0770b8ae09f 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsTestBase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/action/management/v1/ActionsTestBase.java
@@ -80,7 +80,6 @@ public class ActionsTestBase extends RESTAPIServerTestBase {
NOT_IMPLEMENTED_ACTION_TYPE_PATHS.add("/preUpdatePassword");
NOT_IMPLEMENTED_ACTION_TYPE_PATHS.add("/preUpdateProfile");
NOT_IMPLEMENTED_ACTION_TYPE_PATHS.add("/preRegistration");
- NOT_IMPLEMENTED_ACTION_TYPE_PATHS.add("/authentication");
String API_PACKAGE_NAME = "org.wso2.carbon.identity.api.server.action.management.v1";
try {
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/ApplicationManagementSuccessTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/ApplicationManagementSuccessTest.java
index 66aee6d25db..fef332c2ce5 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/ApplicationManagementSuccessTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/ApplicationManagementSuccessTest.java
@@ -90,6 +90,28 @@ public void testGetAllApplications() throws IOException {
}
}
+ @Test
+ public void testGetAllApplicationsExcludingSystemApps() throws IOException {
+
+ Map params = new HashMap<>();
+ params.put("excludeSystemPortals", true);
+ Response response = getResponseOfGet(APPLICATION_MANAGEMENT_API_BASE_PATH, params);
+ response.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_OK);
+ ObjectMapper jsonWriter = new ObjectMapper(new JsonFactory());
+ ApplicationListResponse listResponse = jsonWriter.readValue(response.asString(), ApplicationListResponse.class);
+ Assert.assertFalse(listResponse.getApplications()
+ .stream()
+ .anyMatch(appBasicInfo -> appBasicInfo.getName().equals(ApplicationConstants.CONSOLE_APPLICATION_NAME)),
+ "Default resident service provider '" + ApplicationConstants.CONSOLE_APPLICATION_NAME + "' is listed by the API");
+ Assert.assertFalse(listResponse.getApplications()
+ .stream()
+ .anyMatch(appBasicInfo -> appBasicInfo.getName().equals(ApplicationConstants.MY_ACCOUNT_APPLICATION_NAME)),
+ "Default resident service provider '" + ApplicationConstants.MY_ACCOUNT_APPLICATION_NAME + "' is listed by the API");
+ }
+
@Test
public void testGetResidentApplication() throws IOException {
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/authenticator/management/v1/AuthenticatorSuccessTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/authenticator/management/v1/AuthenticatorSuccessTest.java
new file mode 100644
index 00000000000..b2eeb6f7e31
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/authenticator/management/v1/AuthenticatorSuccessTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
+ *
+ * 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.identity.integration.test.rest.api.server.authenticator.management.v1;
+
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpStatus;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONArray;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+import org.wso2.carbon.automation.engine.context.TestUserMode;
+
+import java.io.IOException;
+
+/**
+ * Tests for happy paths of the authentication Management REST API.
+ */
+public class AuthenticatorSuccessTest extends AuthenticatorTestBase{
+
+
+ @Factory(dataProvider = "restAPIUserConfigProvider")
+ public AuthenticatorSuccessTest(TestUserMode userMode) throws Exception {
+
+ super.init(userMode);
+ this.context = isServer;
+ this.authenticatingUserName = context.getContextTenant().getTenantAdmin().getUserName();
+ this.authenticatingCredential = context.getContextTenant().getTenantAdmin().getPassword();
+ this.tenant = context.getContextTenant().getDomain();
+ }
+
+ @BeforeClass(alwaysRun = true)
+ public void init() throws IOException {
+
+ super.testInit(API_VERSION, swaggerDefinition, tenant);
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void testConclude() {
+
+ super.conclude();
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ public void testInit() {
+
+ RestAssured.basePath = basePath;
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void testFinish() {
+
+ RestAssured.basePath = StringUtils.EMPTY;
+ }
+
+ @DataProvider(name = "restAPIUserConfigProvider")
+ public static Object[][] restAPIUserConfigProvider() {
+
+ return new Object[][]{
+ {TestUserMode.SUPER_TENANT_ADMIN},
+ {TestUserMode.TENANT_ADMIN}
+ };
+ }
+
+ @Test
+ public void getAuthenticators() throws JSONException {
+
+ Response response = getResponseOfGet(AUTHENTICATOR_API_BASE_PATH);
+ response.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_OK);
+
+ JSONArray jsonArray = new JSONArray(response.body().asString());
+ for (int i = 0; i < jsonArray.length(); i++) {
+ JSONObject authenticator = jsonArray.getJSONObject(i);
+ Assert.assertTrue(authenticator.has("id"));
+ Assert.assertTrue(authenticator.has("name"));
+ Assert.assertTrue(authenticator.has("displayName"));
+ Assert.assertTrue(authenticator.has("type"));
+ Assert.assertEquals(authenticator.getString("definedBy"), "SYSTEM");
+ }
+ }
+
+}
+
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/authenticator/management/v1/AuthenticatorTestBase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/authenticator/management/v1/AuthenticatorTestBase.java
new file mode 100644
index 00000000000..677455d1ed0
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/authenticator/management/v1/AuthenticatorTestBase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
+ *
+ * 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.identity.integration.test.rest.api.server.authenticator.management.v1;
+
+import io.restassured.RestAssured;
+import org.apache.commons.lang.StringUtils;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.wso2.identity.integration.test.rest.api.server.common.RESTAPIServerTestBase;
+
+import java.io.IOException;
+
+public class AuthenticatorTestBase extends RESTAPIServerTestBase {
+
+ private static final String API_DEFINITION_NAME = "authenticators.yaml";
+ protected static final String API_VERSION = "v1";
+ protected static final String API_PACKAGE_NAME = "org.wso2.carbon.identity.api.server.authenticators.v1";
+
+ protected static final String AUTHENTICATOR_API_BASE_PATH = "/authenticators";
+
+ protected static String swaggerDefinition;
+
+ static {
+ try {
+ swaggerDefinition = getAPISwaggerDefinition(API_PACKAGE_NAME, API_DEFINITION_NAME);
+ } catch (IOException e) {
+ Assert.fail(String.format("Unable to read the swagger definition %s from %s", API_DEFINITION_NAME,
+ API_PACKAGE_NAME), e);
+ }
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void testConclude() throws Exception {
+
+ super.conclude();
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ public void testInit() {
+
+ RestAssured.basePath = basePath;
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void testFinish() {
+
+ RestAssured.basePath = StringUtils.EMPTY;
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/configs/v1/ConfigSuccessTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/configs/v1/ConfigSuccessTest.java
index 46acc836533..68f39b7b802 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/configs/v1/ConfigSuccessTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/configs/v1/ConfigSuccessTest.java
@@ -104,7 +104,8 @@ public void testGetAuthenticator() throws Exception {
.body("name", equalTo("BasicAuthenticator"))
.body("displayName", equalTo("Username & Password"))
.body("isEnabled", equalTo(true))
- .body("properties", notNullValue());
+ .body("properties", notNullValue())
+ .body("definedBy", equalTo("SYSTEM"));
}
@Test(dependsOnMethods = {"testGetAuthenticator"})
@@ -118,7 +119,8 @@ public void testGetAuthenticators() throws Exception {
.statusCode(HttpStatus.SC_OK)
.body(baseIdentifier + "name", equalTo("BasicAuthenticator"))
.body(baseIdentifier + "displayName", equalTo("Username & Password"))
- .body(baseIdentifier + "isEnabled", equalTo(true));
+ .body(baseIdentifier + "isEnabled", equalTo(true))
+ .body(baseIdentifier + "definedBy", equalTo("SYSTEM"));
}
@Test(dependsOnMethods = {"testGetAuthenticators"})
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/idp/v1/IdPSuccessTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/idp/v1/IdPSuccessTest.java
index 9f624c128d5..ba7dfcc0609 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/idp/v1/IdPSuccessTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/idp/v1/IdPSuccessTest.java
@@ -360,7 +360,8 @@ public void testUpdateIdPFederatedAuthenticator() throws IOException {
response.then()
.log().ifValidationFails()
.assertThat()
- .statusCode(HttpStatus.SC_OK);
+ .statusCode(HttpStatus.SC_OK)
+ .body("definedBy", equalTo("SYSTEM"));
}
@Test(dependsOnMethods = {"testUpdateIdPFederatedAuthenticator"})
@@ -377,6 +378,7 @@ public void testGetIdPFederatedAuthenticator() throws IOException {
.body("isEnabled", equalTo(true))
.body("isDefault", equalTo(true))
.body("properties", notNullValue())
+ .body("definedBy", equalTo("SYSTEM"))
.body("properties.find{ it.key == 'ClientId' }.value", equalTo
("165474950684-7mvqd8m6hieb8mdnffcarnku2aua0tpl.apps.googleusercontent.com"))
.body("properties.find{ it.key == 'ClientSecret' }.value", equalTo("testclientsecret"))
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantFailureTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantFailureTest.java
index d6eff646b71..469907f7f8e 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantFailureTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantFailureTest.java
@@ -26,6 +26,7 @@
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.wso2.carbon.automation.engine.context.TestUserMode;
+import org.wso2.identity.integration.test.rest.api.server.tenant.management.v1.model.TenantResponseModel;
import java.io.IOException;
@@ -37,6 +38,7 @@
public class TenantFailureTest extends TenantManagementBaseTest {
private String tenantId;
+ private String userId;
public TenantFailureTest() throws Exception {
@@ -100,4 +102,51 @@ public void testGetOwnersWithInvalidId() {
validateErrorResponse(response, HttpStatus.SC_BAD_REQUEST, "TM-60014", "random-id");
}
+ @Test void testGetOwnerWithInvalidTenantId() {
+
+ Response response = getResponseOfGet(TENANT_API_BASE_PATH + PATH_SEPARATOR + "random-id" +
+ TENANT_API_OWNER_PATH + PATH_SEPARATOR + "random-id");
+ validateErrorResponse(response, HttpStatus.SC_BAD_REQUEST, "TM-60014", "random-id");
+ }
+
+ @Test
+ public void updateOwnerWithInvalidTenantId() throws IOException {
+
+ String body = readResource("update-owner.json");
+ Response response = getResponseOfPut(TENANT_API_BASE_PATH + PATH_SEPARATOR + "random-id" +
+ TENANT_API_OWNER_PATH + PATH_SEPARATOR + "random-id", body);
+ validateErrorResponse(response, HttpStatus.SC_BAD_REQUEST, "TM-60014", "random-id");
+ }
+
+ @Test
+ public void addTenantWithInvalidClaim() throws IOException {
+
+ Response response = getResponseOfPost(TENANT_API_BASE_PATH, readResource("add-tenant-invalid-claims.json"));
+ validateErrorResponse(response, HttpStatus.SC_PARTIAL_CONTENT, "TM-60021", "Telephone is not in the correct format.");
+ }
+
+ @Test(dependsOnMethods = "addTenantWithInvalidClaim")
+ public void getTenantOwnerWithInvalidOwnerId() {
+
+ Response response = getResponseOfGet(TENANT_API_BASE_PATH + TENANT_DOMAIN_BASE_PATH + PATH_SEPARATOR + "abc3.com");
+
+ TenantResponseModel tenantResponseModel = response.getBody().as(TenantResponseModel.class);
+ tenantId = tenantResponseModel.getId();
+ userId = tenantResponseModel.getOwners().get(0).getId();
+
+ response = getResponseOfGet(TENANT_API_BASE_PATH + PATH_SEPARATOR + tenantId +
+ TENANT_API_OWNER_PATH + PATH_SEPARATOR + "random-id");
+ validateErrorResponse(response, HttpStatus.SC_BAD_REQUEST, "TM-60020", tenantId);
+ }
+
+ @Test(dependsOnMethods = "getTenantOwnerWithInvalidOwnerId")
+ public void updateTenantOwnerWithInvalidOwnerId() throws IOException {
+
+ String body = readResource("update-owner.json");
+ Response response = getResponseOfPut(TENANT_API_BASE_PATH + PATH_SEPARATOR + tenantId +
+ TENANT_API_OWNER_PATH + PATH_SEPARATOR + "random-id", body);
+ validateErrorResponse(response, HttpStatus.SC_BAD_REQUEST, "TM-60020", tenantId);
+ }
+
+
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantSuccessTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantSuccessTest.java
index e78f1897db9..b259d5c38a7 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantSuccessTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/TenantSuccessTest.java
@@ -43,6 +43,7 @@ public class TenantSuccessTest extends TenantManagementBaseTest {
private String tenantId;
private String userId;
+ private static final String TELEPHONE_CLAIM = "http://wso2.org/claims/telephone";
public TenantSuccessTest() throws Exception {
@@ -152,4 +153,34 @@ public void testGetOwners() throws Exception {
.body(activeStatusIdentifier, notNullValue())
.body(activeStatusIdentifier + ".username", equalTo("kim"));
}
+
+ @Test(dependsOnMethods = {"testGetTenant"})
+ public void testUpdateOwner() throws Exception {
+
+ String body = readResource("update-owner.json");
+ Response response = getResponseOfPut(TENANT_API_BASE_PATH + PATH_SEPARATOR + tenantId +
+ TENANT_API_OWNER_PATH + PATH_SEPARATOR + userId, body);
+
+ response.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_OK);
+ }
+
+ @Test(dependsOnMethods = {"testUpdateOwner"})
+ public void testGetOwner() {
+
+ Response response = getResponseOfGet(TENANT_API_BASE_PATH + PATH_SEPARATOR + tenantId +
+ TENANT_API_OWNER_PATH + PATH_SEPARATOR + userId + "?additionalClaims=" + TELEPHONE_CLAIM);
+
+ String claimsIdentifier = "additionalClaims.find{ it.claim == '" + TELEPHONE_CLAIM + "' }";
+
+ response.then()
+ .log().ifValidationFails()
+ .assertThat()
+ .statusCode(HttpStatus.SC_OK)
+ .body("username", equalTo("kim"))
+ .body( "lastname", equalTo("lee"))
+ .body(claimsIdentifier + ".value", equalTo("+94 77 123 4568"));
+ }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaMeTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaMeTestCase.java
index c66318a2438..4e8c4c67cf5 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaMeTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaMeTestCase.java
@@ -21,6 +21,7 @@
import io.restassured.RestAssured;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHeaders;
@@ -46,6 +47,7 @@
import org.wso2.identity.integration.test.scim2.rest.api.SCIM2BaseTest;
import java.rmi.RemoteException;
+import java.util.Arrays;
import java.util.LinkedHashMap;
import static org.hamcrest.CoreMatchers.notNullValue;
@@ -125,7 +127,10 @@ public void init() throws RemoteException, InterruptedException {
public void testFinish() {
try {
- claimMetadataManagementServiceClient.removeClaimDialect(CUSTOM_SCHEMA_URI);
+ claimMetadataManagementServiceClient.removeExternalClaim(CUSTOM_SCHEMA_URI, COUNTRY_CLAIM_ATTRIBUTE_URI);
+ claimMetadataManagementServiceClient.removeExternalClaim(CUSTOM_SCHEMA_URI,
+ MANAGER_EMAIL_CLAIM_ATTRIBUTE_URI);
+ claimMetadataManagementServiceClient.removeExternalClaim(CUSTOM_SCHEMA_URI, MANAGER_CLAIM_ATTRIBUTE_URI);
claimMetadataManagementServiceClient.removeLocalClaim(MANAGER_LOCAL_CLAIM_URI);
} catch (RemoteException | ClaimMetadataManagementServiceClaimMetadataException e) {
log.error(e);
@@ -139,7 +144,7 @@ public void testInit() {
RestAssured.basePath = basePath;
}
- @Test(description = "Creates custom schema dialect, simple attribute and complex attributes.")
+ @Test(description = "Creates simple attribute and complex attributes in urn:scim:wso2:schema.")
private void createClaims() throws Exception {
AutomationContext context = new AutomationContext("IDENTITY", mode);
@@ -147,17 +152,19 @@ private void createClaims() throws Exception {
loginLogoutClient = new LoginLogoutClient(context);
cookie = loginLogoutClient.login();
claimMetadataManagementServiceClient = new ClaimMetadataManagementServiceClient(backendURL, cookie);
- int claimDialect = claimMetadataManagementServiceClient.getClaimDialects().length;
- // Set custom schema dialect.
- ClaimDialectDTO claimDialectDTO = new ClaimDialectDTO();
- claimDialectDTO.setClaimDialectURI(CUSTOM_SCHEMA_URI);
- claimMetadataManagementServiceClient.addClaimDialect(claimDialectDTO);
-
- //Set claims
+ //Set claims.
setSimpleAttribute();
setComplexAttribute();
- assertEquals(claimMetadataManagementServiceClient.getClaimDialects().length, claimDialect + 1);
+
+ ExternalClaimDTO[] externalClaimDTOs =
+ claimMetadataManagementServiceClient.getExternalClaims(CUSTOM_SCHEMA_URI);
+ Assert.assertTrue(Arrays.stream(externalClaimDTOs)
+ .anyMatch(claim -> StringUtils.equals(claim.getExternalClaimURI(), COUNTRY_CLAIM_ATTRIBUTE_URI)));
+ Assert.assertTrue(Arrays.stream(externalClaimDTOs)
+ .anyMatch(claim -> StringUtils.equals(claim.getExternalClaimURI(), MANAGER_CLAIM_ATTRIBUTE_URI)));
+ Assert.assertTrue(Arrays.stream(externalClaimDTOs)
+ .anyMatch(claim -> StringUtils.equals(claim.getExternalClaimURI(), MANAGER_EMAIL_CLAIM_ATTRIBUTE_URI)));
}
@Test(dependsOnMethods = "createClaims", description = "Create user with custom schema dialect.")
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaUserTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaUserTestCase.java
index 4c992866d75..57ba44cd3ba 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaUserTestCase.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/scim2/rest/api/customSchema/SCIM2CustomSchemaUserTestCase.java
@@ -48,6 +48,7 @@
import org.wso2.identity.integration.test.scim2.rest.api.SCIMUtils;
import java.rmi.RemoteException;
+import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
@@ -123,7 +124,10 @@ public void init() throws RemoteException, InterruptedException {
public void testFinish() {
try {
- claimMetadataManagementServiceClient.removeClaimDialect(CUSTOM_SCHEMA_URI);
+ claimMetadataManagementServiceClient.removeExternalClaim(CUSTOM_SCHEMA_URI, COUNTRY_CLAIM_ATTRIBUTE_URI);
+ claimMetadataManagementServiceClient.removeExternalClaim(CUSTOM_SCHEMA_URI,
+ MANAGER_EMAIL_CLAIM_ATTRIBUTE_URI);
+ claimMetadataManagementServiceClient.removeExternalClaim(CUSTOM_SCHEMA_URI, MANAGER_CLAIM_ATTRIBUTE_URI);
claimMetadataManagementServiceClient.removeLocalClaim(MANAGER_LOCAL_CLAIM_URI);
} catch (RemoteException | ClaimMetadataManagementServiceClaimMetadataException e) {
log.error(e);
@@ -137,7 +141,7 @@ public void testInit() {
RestAssured.basePath = basePath;
}
- @Test(description = "Creates custom schema dialect, simple attribute and complex attributes.")
+ @Test(description = "Creates simple attribute and complex attributes in urn:scim:wso2:schema.")
private void createClaims() throws Exception {
AutomationContext context = new AutomationContext("IDENTITY", mode);
@@ -145,17 +149,19 @@ private void createClaims() throws Exception {
loginLogoutClient = new LoginLogoutClient(context);
cookie = loginLogoutClient.login();
claimMetadataManagementServiceClient = new ClaimMetadataManagementServiceClient(backendURL, cookie);
- int claimDialect = claimMetadataManagementServiceClient.getClaimDialects().length;
- // Set custom schema dialect.
- ClaimDialectDTO claimDialectDTO = new ClaimDialectDTO();
- claimDialectDTO.setClaimDialectURI(CUSTOM_SCHEMA_URI);
- claimMetadataManagementServiceClient.addClaimDialect(claimDialectDTO);
-
- //Set claims
+ //Set claims.
setSimpleAttribute();
setComplexAttribute();
- assertEquals(claimMetadataManagementServiceClient.getClaimDialects().length, claimDialect + 1);
+
+ ExternalClaimDTO[] externalClaimDTOs =
+ claimMetadataManagementServiceClient.getExternalClaims(CUSTOM_SCHEMA_URI);
+ Assert.assertTrue(Arrays.stream(externalClaimDTOs)
+ .anyMatch(claim -> StringUtils.equals(claim.getExternalClaimURI(), COUNTRY_CLAIM_ATTRIBUTE_URI)));
+ Assert.assertTrue(Arrays.stream(externalClaimDTOs)
+ .anyMatch(claim -> StringUtils.equals(claim.getExternalClaimURI(), MANAGER_CLAIM_ATTRIBUTE_URI)));
+ Assert.assertTrue(Arrays.stream(externalClaimDTOs)
+ .anyMatch(claim -> StringUtils.equals(claim.getExternalClaimURI(), MANAGER_EMAIL_CLAIM_ATTRIBUTE_URI)));
}
@Test(dependsOnMethods = "createClaims", description = "Create user with custom schema dialect.")
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/util/Utils.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/util/Utils.java
index c7d5b6b5d32..0d31062c812 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/util/Utils.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/util/Utils.java
@@ -699,4 +699,23 @@ public static String getBasicAuthHeader(User userInfo) {
BasicAuthInfo encodedBasicAuthInfo = (BasicAuthInfo) basicAuthHandler.getAuthenticationToken(basicAuthInfo);
return encodedBasicAuthInfo.getAuthorizationHeader();
}
+
+ /**
+ * Get Java Major Version from System Property.
+ *
+ * @return Java Major Version
+ */
+ public static int getJavaVersion() {
+
+ String version = System.getProperty("java.version");
+ if (version.startsWith("1.")) {
+ version = version.substring(2, 3);
+ } else {
+ int dot = version.indexOf(".");
+ if (dot != -1) {
+ version = version.substring(0, dot);
+ }
+ }
+ return Integer.parseInt(version);
+ }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/IS/identity_new_resource_openjdknashorn.toml b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/IS/identity_new_resource_openjdknashorn.toml
new file mode 100644
index 00000000000..57fce1ac3d3
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/IS/identity_new_resource_openjdknashorn.toml
@@ -0,0 +1,36 @@
+[server]
+hostname = "localhost"
+node_ip = "127.0.0.1"
+base_path = "https://$ref{server.hostname}:${carbon.management.port}"
+
+[super_admin]
+username = "admin"
+password = "admin"
+create_admin_account = true
+
+[user_store]
+type = "database_unique_id"
+
+[database.identity_db]
+driver = "$env{IDENTITY_DATABASE_DRIVER}"
+url = "$env{IDENTITY_DATABASE_URL}"
+username = "$env{IDENTITY_DATABASE_USERNAME}"
+password = "$env{IDENTITY_DATABASE_PASSWORD}"
+
+[database.shared_db]
+driver = "$env{SHARED_DATABASE_DRIVER}"
+url = "$env{SHARED_DATABASE_URL}"
+username = "$env{SHARED_DATABASE_USERNAME}"
+password = "$env{SHARED_DATABASE_PASSWORD}"
+
+[keystore.primary]
+file_name = "wso2carbon.p12"
+password = "wso2carbon"
+
+[[resource.access_control]]
+context = "(.*)/sample-auth/(.*)"
+secure = false
+http_method = "all"
+
+[AdaptiveAuth]
+ScriptEngine = "openjdkNashorn"
diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/IS/scriptEngine/openjdknashorn_script_engine_config.toml b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/IS/scriptEngine/openjdknashorn_script_engine_config.toml
new file mode 100644
index 00000000000..b8a9d3dc55c
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/IS/scriptEngine/openjdknashorn_script_engine_config.toml
@@ -0,0 +1,42 @@
+[server]
+hostname = "localhost"
+node_ip = "127.0.0.1"
+base_path = "https://$ref{server.hostname}:${carbon.management.port}"
+
+[super_admin]
+username = "admin"
+password = "admin"
+create_admin_account = true
+
+[user_store]
+type = "database_unique_id"
+
+[database.identity_db]
+type = "h2"
+url = "jdbc:h2:./repository/database/WSO2IDENTITY_DB;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=60000"
+username = "wso2carbon"
+password = "wso2carbon"
+
+[database.shared_db]
+type = "h2"
+url = "jdbc:h2:./repository/database/WSO2SHARED_DB;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=60000"
+username = "wso2carbon"
+password = "wso2carbon"
+
+[keystore.primary]
+file_name = "wso2carbon.p12"
+password = "wso2carbon"
+
+[truststore]
+file_name="client-truststore.p12"
+password="wso2carbon"
+type="PKCS12"
+
+[account_recovery.endpoint.auth]
+hash= "66cd9688a2ae068244ea01e70f0e230f5623b7fa4cdecb65070a09ec06452262"
+
+[identity.auth_framework.endpoint]
+app_password= "dashboard"
+
+[AdaptiveAuth]
+ScriptEngine = "openjdkNashorn"
diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/add-tenant-invalid-claims.json b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/add-tenant-invalid-claims.json
new file mode 100644
index 00000000000..123930163b5
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/add-tenant-invalid-claims.json
@@ -0,0 +1,23 @@
+{
+ "domain": "abc3.com",
+ "owners": [
+ {
+ "username": "kim",
+ "password": "kim123",
+ "email": "kim@wso2.com",
+ "firstname": "kim",
+ "lastname": "kim",
+ "provisioningMethod": "inline-password",
+ "additionalClaims": [
+ {
+ "claim": "http://wso2.org/claims/telephone",
+ "value": "+94 77 123 456"
+ },
+ {
+ "claim": "http://wso2.org/claims/country",
+ "value": "SriLanka"
+ }
+ ]
+ }
+ ]
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/update-owner.json b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/update-owner.json
new file mode 100644
index 00000000000..b82e2bb3137
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/tenant/management/v1/update-owner.json
@@ -0,0 +1,11 @@
+{
+ "firstname": "kim",
+ "lastname": "lee",
+ "email": "kim@wso2.com",
+ "additionalClaims": [
+ {
+ "claim": "http://wso2.org/claims/telephone",
+ "value": "+94 77 123 4568"
+ }
+ ]
+}
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 6cba73daa60..394603ebcb2 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
@@ -137,6 +137,7 @@
+
@@ -144,6 +145,7 @@
+
@@ -232,6 +234,7 @@
+
@@ -249,10 +252,13 @@
-
+
-
@@ -261,7 +267,17 @@
+
+
@@ -270,9 +286,17 @@
+
+
@@ -315,7 +339,6 @@
-
@@ -362,7 +385,7 @@
-
+
diff --git a/modules/local-authenticators/pom.xml b/modules/local-authenticators/pom.xml
index 72e99fd73ba..57fff0e105d 100644
--- a/modules/local-authenticators/pom.xml
+++ b/modules/local-authenticators/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/modules/oauth2-grant-types/pom.xml b/modules/oauth2-grant-types/pom.xml
index 94f8db3ac14..40317e41545 100644
--- a/modules/oauth2-grant-types/pom.xml
+++ b/modules/oauth2-grant-types/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/p2-profile-gen/pom.xml b/modules/p2-profile-gen/pom.xml
index 616e72fe534..2c18d19c23d 100644
--- a/modules/p2-profile-gen/pom.xml
+++ b/modules/p2-profile-gen/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/provisioning-connectors/pom.xml b/modules/provisioning-connectors/pom.xml
index 5f3faa33efd..20f702b011a 100644
--- a/modules/provisioning-connectors/pom.xml
+++ b/modules/provisioning-connectors/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/modules/social-authenticators/pom.xml b/modules/social-authenticators/pom.xml
index 4b52ce3e771..da6a28b08cc 100644
--- a/modules/social-authenticators/pom.xml
+++ b/modules/social-authenticators/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/modules/styles/pom.xml b/modules/styles/pom.xml
index a316be0a1ef..2f61bdf3b33 100644
--- a/modules/styles/pom.xml
+++ b/modules/styles/pom.xml
@@ -20,7 +20,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/modules/styles/product/pom.xml b/modules/styles/product/pom.xml
index f59e1aa4cea..64b39e4233d 100644
--- a/modules/styles/product/pom.xml
+++ b/modules/styles/product/pom.xml
@@ -20,7 +20,7 @@
org.wso2.is
identity-server-styles-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/tests-utils/admin-services/pom.xml b/modules/tests-utils/admin-services/pom.xml
index 52f0b34f973..af08dc6d12d 100644
--- a/modules/tests-utils/admin-services/pom.xml
+++ b/modules/tests-utils/admin-services/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-integration-tests-utils
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/tests-utils/admin-stubs/pom.xml b/modules/tests-utils/admin-stubs/pom.xml
index a87633b391d..fb85b873984 100644
--- a/modules/tests-utils/admin-stubs/pom.xml
+++ b/modules/tests-utils/admin-stubs/pom.xml
@@ -21,7 +21,7 @@
org.wso2.is
identity-integration-tests-utils
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../pom.xml
diff --git a/modules/tests-utils/pom.xml b/modules/tests-utils/pom.xml
index 73534fc5f73..27f14c46ab3 100644
--- a/modules/tests-utils/pom.xml
+++ b/modules/tests-utils/pom.xml
@@ -19,7 +19,7 @@
org.wso2.is
identity-server-parent
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
../../pom.xml
diff --git a/pom.xml b/pom.xml
index 54b4b510bd7..0d10c824058 100755
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
identity-server-parent
pom
WSO2 Identity Server
- 7.1.0-m2-SNAPSHOT
+ 7.1.0-m4-SNAPSHOT
WSO2 Identity Server
http://wso2.org/projects/identity
@@ -2244,6 +2244,11 @@
org.wso2.carbon.extension.identity.helper
${identity.extension.utils}
+
+ com.nimbusds
+ nimbus-jose-jwt
+ ${nimbus-jose-jwt.version}
+
@@ -2382,12 +2387,12 @@
- 7.0.162
+ 7.0.169
5.11.43
5.10.2
- 5.11.9
+ 5.11.10
5.7.7
- 3.4.94
+ 3.4.97
5.5.10
@@ -2403,7 +2408,7 @@
1.9.12
- 1.9.9
+ 1.9.11
@@ -2473,20 +2478,20 @@
2.0.17
- 1.2.234
+ 1.2.240
1.3.43
5.5.9
5.5.9
2.3.2
2.5.17
- 1.1.12
+ 1.1.13
1.2.65
- 2.30.0
- 2.8.20
- 2.4.44
+ 2.30.14
+ 2.8.33
+ 2.4.47
1.6.378
@@ -2496,13 +2501,13 @@
4.10.23
- 1.0.12
+ 1.0.13
4.12.29
- 4.10.9
+ 4.10.12
4.8.35
- 4.11.24
+ 4.11.27
1.3.12
5.2.58
2.0.27
@@ -2635,6 +2640,7 @@
2.0.1
2.0.1
1.15.3
+ 9.41.2