From 94780fe18b7fc0cb5213451f43b7581b432c77ae Mon Sep 17 00:00:00 2001 From: Thilina Shashimal Senarath Date: Wed, 14 Aug 2024 11:18:14 +0530 Subject: [PATCH 1/4] add access token attributes integration test --- .../OIDCAccessTokenAttributesTestCase.java | 176 ++++++++++++++++++ .../v1/model/AccessTokenConfiguration.java | 48 +++++ .../src/test/resources/testng.xml | 1 + 3 files changed, 225 insertions(+) create mode 100644 modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java new file mode 100644 index 00000000000..0d70c763237 --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java @@ -0,0 +1,176 @@ +package org.wso2.identity.integration.test.oidc; + +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import io.restassured.RestAssured; +import io.restassured.response.Response; +import org.apache.http.HttpStatus; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.identity.integration.test.oidc.bean.OIDCApplication; +import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AccessTokenConfiguration; +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.InboundProtocols; +import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration; +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 static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.notNullValue; + +public class OIDCAccessTokenAttributesTestCase extends OIDCAbstractIntegrationTest { + + private static final String OAUTH2_TOKEN_ENDPOINT_URI = "/oauth2/token"; + private static final String SERVICES = "/services"; + private OIDCApplication application; + protected String refreshToken; + protected String sessionDataKey; + + @BeforeClass(alwaysRun = true) + public void testInit() throws Exception { + + super.init(); + + RestAssured.baseURI = backendURL.replace(SERVICES, ""); + + // Create a user + OIDCUtilTest.initUser(); + createUser(OIDCUtilTest.user); + + // Create application + OIDCUtilTest.initApplications(); + application = OIDCUtilTest.applications.get(OIDCUtilTest.playgroundAppTwoAppName); + createApplication(application); + } + + @AfterClass(alwaysRun = true) + public void testClear() throws Exception { + + deleteUser(OIDCUtilTest.user); + deleteApplication(application); + clear(); + } + + @Test(groups = "wso2.is", description = "Validate access token attributes with password grant") + public void testValidateAccessTokenAttributesWithPasswordGrant() throws Exception { + + Map params = new HashMap<>(); + params.put("grant_type", OAuth2Constant.OAUTH2_GRANT_TYPE_RESOURCE_OWNER); + params.put("scope", ""); + params.put("username", OIDCUtilTest.user.getUserName()); + params.put("password", OIDCUtilTest.user.getPassword()); + + Response response = getResponseOfFormPostWithAuth(OAUTH2_TOKEN_ENDPOINT_URI, params, new HashMap<>(), + application.getClientId(), application.getClientSecret()); + + response.then() + .log().ifValidationFails() + .assertThat() + .statusCode(HttpStatus.SC_OK) + .body("access_token", notNullValue()) + .body("refresh_token", notNullValue()); + + String accessToken = response.then().extract().path("access_token"); + refreshToken = response.then().extract().path("refresh_token"); + Assert.assertNotNull(accessToken, "Access token is null"); + JWTClaimsSet jwtClaimsSet = SignedJWT.parse(accessToken).getJWTClaimsSet(); + Assert.assertNotNull(jwtClaimsSet.getClaim("username"), "Invalid is null."); + + } + + @Test(groups = "wso2.is", description = "Validate access token attributes with refresh grant", + dependsOnMethods = "testValidateAccessTokenAttributesWithPasswordGrant") + public void testValidateAccessTokenAttributesWithRefreshGrant() throws Exception { + + Map params = new HashMap<>(); + params.put("grant_type", OAuth2Constant.OAUTH2_GRANT_TYPE_REFRESH_TOKEN); + params.put(OAuth2Constant.OAUTH2_GRANT_TYPE_REFRESH_TOKEN, refreshToken); + + Response response = getResponseOfFormPostWithAuth(OAUTH2_TOKEN_ENDPOINT_URI, params, new HashMap<>(), + application.getClientId(), application.getClientSecret()); + + response.then() + .log().ifValidationFails() + .assertThat() + .statusCode(HttpStatus.SC_OK) + .body("access_token", notNullValue()) + .body("refresh_token", notNullValue()); + + String accessToken = response.then().extract().path("access_token"); + refreshToken = response.then().extract().path("refresh_token"); + Assert.assertNotNull(accessToken, "Access token is null"); + JWTClaimsSet jwtClaimsSet = SignedJWT.parse(accessToken).getJWTClaimsSet(); + Assert.assertNotNull(jwtClaimsSet.getClaim("username"), "Invalid is null."); + } + + /** + * Invoke given endpointUri for Form POST request with given body, headers and Basic authentication credentials. + * + * @param endpointUri endpoint to be invoked. + * @param params map of parameters to be added to the request. + * @param headers map of headers to be added to the request. + * @param username basic auth username. + * @param password basic auth password. + * @return response. + */ + protected Response getResponseOfFormPostWithAuth(String endpointUri, Map params, Map + headers, String username, String password) { + + return given().auth().preemptive().basic(username, password) + .headers(headers) + .params(params) + .when() + .post(endpointUri); + } + + /** + * Create an OIDC application. + * + * @param application application instance. + * @throws Exception If an error creating an application. + */ + public void createApplication(OIDCApplication application) throws Exception { + + ApplicationModel applicationModel = new ApplicationModel(); + createAccessTokenAttributesEnabledApplication(applicationModel, application); + } + + private void createAccessTokenAttributesEnabledApplication(ApplicationModel applicationModel, + OIDCApplication application) throws Exception { + + List grantTypes = new ArrayList<>(); + Collections.addAll(grantTypes, OAuth2Constant.OAUTH2_GRANT_TYPE_RESOURCE_OWNER, + OAuth2Constant.OAUTH2_GRANT_TYPE_REFRESH_TOKEN); + + OpenIDConnectConfiguration oidcConfig = new OpenIDConnectConfiguration(); + oidcConfig.setGrantTypes(grantTypes); + oidcConfig.addCallbackURLsItem(application.getCallBackURL()); + + AccessTokenConfiguration accessTokenConfig = new AccessTokenConfiguration().type("JWT"); + accessTokenConfig.setUserAccessTokenExpiryInSeconds(3600L); + accessTokenConfig.setApplicationAccessTokenExpiryInSeconds(3600L); + // Add access token attributes + List accessTokenAttributes = new ArrayList<>(); + Collections.addAll(accessTokenAttributes, "username", "email"); + accessTokenConfig.setAccessTokenAttributes(accessTokenAttributes); + + oidcConfig.setAccessToken(accessTokenConfig); + + applicationModel.setName(application.getApplicationName()); + applicationModel.setInboundProtocolConfiguration(new InboundProtocols().oidc(oidcConfig)); + + String applicationId = addApplication(applicationModel); + oidcConfig = getOIDCInboundDetailsOfApplication(applicationId); + + application.setApplicationId(applicationId); + application.setClientId(oidcConfig.getClientId()); + application.setClientSecret(oidcConfig.getClientSecret()); + } +} diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/AccessTokenConfiguration.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/AccessTokenConfiguration.java index a97cf611c03..1b063d47347 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/AccessTokenConfiguration.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/AccessTokenConfiguration.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import javax.validation.Valid; @@ -31,6 +33,8 @@ public class AccessTokenConfiguration { private Long applicationAccessTokenExpiryInSeconds; private Boolean revokeTokensWhenIDPSessionTerminated; private Boolean validateTokenBinding; + private List accessTokenAttributes = null; + private Boolean accessTokenAttributesEnabled; /** **/ @@ -122,6 +126,50 @@ public void setRevokeTokensWhenIDPSessionTerminated(Boolean revokeTokensWhenIDPS this.revokeTokensWhenIDPSessionTerminated = revokeTokensWhenIDPSessionTerminated; } + /** + **/ + public AccessTokenConfiguration accessTokenAttributes(List accessTokenAttributes) { + + this.accessTokenAttributes = accessTokenAttributes; + return this; + } + + @ApiModelProperty(value = "") + @JsonProperty("accessTokenAttributes") + @Valid + public List getAccessTokenAttributes() { + return accessTokenAttributes; + } + public void setAccessTokenAttributes(List accessTokenAttributes) { + this.accessTokenAttributes = accessTokenAttributes; + } + + public AccessTokenConfiguration addAccessTokenAttributesItem(String accessTokenAttributesItem) { + if (this.accessTokenAttributes == null) { + this.accessTokenAttributes = new ArrayList<>(); + } + this.accessTokenAttributes.add(accessTokenAttributesItem); + return this; + } + + /** + **/ + public AccessTokenConfiguration accessTokenAttributesEnabled(Boolean accessTokenAttributesEnabled) { + + this.accessTokenAttributesEnabled = accessTokenAttributesEnabled; + return this; + } + + @ApiModelProperty(value = "") + @JsonProperty("accessTokenAttributesEnabled") + @Valid + public Boolean getAccessTokenAttributesEnabled() { + return accessTokenAttributesEnabled; + } + public void setAccessTokenAttributesEnabled(Boolean accessTokenAttributesEnabled) { + this.accessTokenAttributesEnabled = accessTokenAttributesEnabled; + } + @Override public boolean equals(Object o) { 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 0058aecff0c..91ffd964290 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 @@ + From e5297d0efa331cd3c3494ed96a7867682997fd3b Mon Sep 17 00:00:00 2001 From: Thilina Shashimal Senarath Date: Wed, 14 Aug 2024 11:29:06 +0530 Subject: [PATCH 2/4] add license header --- .../OIDCAccessTokenAttributesTestCase.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java index 0d70c763237..eb2150289fa 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java @@ -1,3 +1,21 @@ +/* + * 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.oidc; import com.nimbusds.jwt.JWTClaimsSet; From 7c2d38914e1002ce49b3d8f674eb26fe4fcd2444 Mon Sep 17 00:00:00 2001 From: Thilina Shashimal Senarath Date: Wed, 14 Aug 2024 11:30:14 +0530 Subject: [PATCH 3/4] fix error messsage --- .../test/oidc/OIDCAccessTokenAttributesTestCase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java index eb2150289fa..b36231bd671 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java @@ -99,7 +99,7 @@ public void testValidateAccessTokenAttributesWithPasswordGrant() throws Exceptio refreshToken = response.then().extract().path("refresh_token"); Assert.assertNotNull(accessToken, "Access token is null"); JWTClaimsSet jwtClaimsSet = SignedJWT.parse(accessToken).getJWTClaimsSet(); - Assert.assertNotNull(jwtClaimsSet.getClaim("username"), "Invalid is null."); + Assert.assertNotNull(jwtClaimsSet.getClaim("username"), "Username is null."); } @@ -125,7 +125,7 @@ public void testValidateAccessTokenAttributesWithRefreshGrant() throws Exception refreshToken = response.then().extract().path("refresh_token"); Assert.assertNotNull(accessToken, "Access token is null"); JWTClaimsSet jwtClaimsSet = SignedJWT.parse(accessToken).getJWTClaimsSet(); - Assert.assertNotNull(jwtClaimsSet.getClaim("username"), "Invalid is null."); + Assert.assertNotNull(jwtClaimsSet.getClaim("username"), "Username is null."); } /** From b17c76348d13ec3706412f8f02f794f6d752f987 Mon Sep 17 00:00:00 2001 From: Thilina Shashimal Senarath Date: Thu, 15 Aug 2024 10:13:57 +0530 Subject: [PATCH 4/4] add negative test cases --- .../OIDCAccessTokenAttributesTestCase.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java index b36231bd671..e81559fea6c 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oidc/OIDCAccessTokenAttributesTestCase.java @@ -48,6 +48,7 @@ public class OIDCAccessTokenAttributesTestCase extends OIDCAbstractIntegrationTe private static final String OAUTH2_TOKEN_ENDPOINT_URI = "/oauth2/token"; private static final String SERVICES = "/services"; private OIDCApplication application; + private OpenIDConnectConfiguration oidcInboundConfig; protected String refreshToken; protected String sessionDataKey; @@ -128,6 +129,76 @@ public void testValidateAccessTokenAttributesWithRefreshGrant() throws Exception Assert.assertNotNull(jwtClaimsSet.getClaim("username"), "Username is null."); } + @Test(groups = "wso2.is", description = "Update access token attributes of the application", + dependsOnMethods = "testValidateAccessTokenAttributesWithRefreshGrant") + public void testUpdateAccessTokenAttributes() throws Exception { + + AccessTokenConfiguration accessTokenConfig = new AccessTokenConfiguration().type("JWT"); + accessTokenConfig.setUserAccessTokenExpiryInSeconds(3600L); + accessTokenConfig.setApplicationAccessTokenExpiryInSeconds(3600L); + // Add access token attributes + accessTokenConfig.setAccessTokenAttributes(new ArrayList<>()); + oidcInboundConfig.setAccessToken(accessTokenConfig); + updateApplicationInboundConfig(application.getApplicationId(), oidcInboundConfig, OIDC); + + OpenIDConnectConfiguration updatedOidcInboundConfig = + getOIDCInboundDetailsOfApplication(application.getApplicationId()); + Assert.assertTrue(updatedOidcInboundConfig.getAccessToken().getAccessTokenAttributes().isEmpty(), + "Access token attribute should be empty."); + } + + @Test(groups = "wso2.is", description = "Validate access token attributes for empty allowed attributes", + dependsOnMethods = "testUpdateAccessTokenAttributes") + public void testValidateAccessTokenAttributesForEmptyAllowedAttributes() throws Exception { + + Map params = new HashMap<>(); + params.put("grant_type", OAuth2Constant.OAUTH2_GRANT_TYPE_RESOURCE_OWNER); + params.put("scope", ""); + params.put("username", OIDCUtilTest.user.getUserName()); + params.put("password", OIDCUtilTest.user.getPassword()); + + Response response = getResponseOfFormPostWithAuth(OAUTH2_TOKEN_ENDPOINT_URI, params, new HashMap<>(), + application.getClientId(), application.getClientSecret()); + + response.then() + .log().ifValidationFails() + .assertThat() + .statusCode(HttpStatus.SC_OK) + .body("access_token", notNullValue()) + .body("refresh_token", notNullValue()); + + String accessToken = response.then().extract().path("access_token"); + refreshToken = response.then().extract().path("refresh_token"); + Assert.assertNotNull(accessToken, "Access token is null"); + JWTClaimsSet jwtClaimsSet = SignedJWT.parse(accessToken).getJWTClaimsSet(); + Assert.assertNull(jwtClaimsSet.getClaim("username"), "Username is not null."); + } + + @Test(groups = "wso2.is", description = "Validate access token attributes for empty allowed attributes with " + + "refresh grant", dependsOnMethods = "testValidateAccessTokenAttributesForEmptyAllowedAttributes") + public void testValidateAccessTokenAttributesForEmptyAllowedAttributesWithRefreshGrant() throws Exception { + + Map params = new HashMap<>(); + params.put("grant_type", OAuth2Constant.OAUTH2_GRANT_TYPE_REFRESH_TOKEN); + params.put(OAuth2Constant.OAUTH2_GRANT_TYPE_REFRESH_TOKEN, refreshToken); + + Response response = getResponseOfFormPostWithAuth(OAUTH2_TOKEN_ENDPOINT_URI, params, new HashMap<>(), + application.getClientId(), application.getClientSecret()); + + response.then() + .log().ifValidationFails() + .assertThat() + .statusCode(HttpStatus.SC_OK) + .body("access_token", notNullValue()) + .body("refresh_token", notNullValue()); + + String accessToken = response.then().extract().path("access_token"); + refreshToken = response.then().extract().path("refresh_token"); + Assert.assertNotNull(accessToken, "Access token is null"); + JWTClaimsSet jwtClaimsSet = SignedJWT.parse(accessToken).getJWTClaimsSet(); + Assert.assertNull(jwtClaimsSet.getClaim("username"), "Username is not null."); + } + /** * Invoke given endpointUri for Form POST request with given body, headers and Basic authentication credentials. * @@ -186,6 +257,7 @@ private void createAccessTokenAttributesEnabledApplication(ApplicationModel appl String applicationId = addApplication(applicationModel); oidcConfig = getOIDCInboundDetailsOfApplication(applicationId); + oidcInboundConfig = oidcConfig; application.setApplicationId(applicationId); application.setClientId(oidcConfig.getClientId());