diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java index 6ccffbb41e..662052f9e7 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2013-2025, 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 @@ -233,6 +233,8 @@ public class OAuthServerConfiguration { private List supportedIdTokenEncryptionMethods = new ArrayList<>(); private String userInfoJWTSignatureAlgorithm = "SHA256withRSA"; private boolean userInfoMultiValueSupportEnabled = true; + private boolean userInfoInternalPrefixedRolesClaimEnabled = false; + private String authContextTTL = "15L"; // property added to fix IDENTITY-4551 in backward compatible manner private boolean useMultiValueSeparatorForAuthContextToken = true; @@ -1575,6 +1577,16 @@ public boolean getUserInfoMultiValueSupportEnabled() { return userInfoMultiValueSupportEnabled; } + /** + * Returns whether Internal prefix should be appended for roles claim of the userinfo response. + * + * @return True if Internal prefix value should be appended for the role claim of userinfo response. + */ + public boolean getUserInfoInternalPrefixedRolesClaimEnabled() { + + return userInfoInternalPrefixedRolesClaimEnabled; + } + public String getConsumerDialectURI() { return consumerDialectURI; } @@ -3503,6 +3515,15 @@ private void parseOpenIDConnectConfig(OMElement oauthConfigElem) { userInfoMultiValueSupportEnabled = Boolean.parseBoolean( userInfoMultiValueSupportEnabledElem.getText().trim()); } + + OMElement userInfoInternalPrefixedRolesClaim = openIDConnectConfigElem + .getFirstChildWithName(getQNameWithIdentityNS(ConfigElements + .OPENID_CONNECT_USERINFO_INTERNAL_PREFIXED_ROLE_CLAIM_ENABLED)); + if (userInfoInternalPrefixedRolesClaim != null) { + userInfoInternalPrefixedRolesClaimEnabled = Boolean.parseBoolean( + userInfoInternalPrefixedRolesClaim.getText().trim()); + } + if (openIDConnectConfigElem.getFirstChildWithName( getQNameWithIdentityNS(ConfigElements.OPENID_CONNECT_SIGN_JWT_WITH_SP_KEY)) != null) { isJWTSignedWithSPKey = Boolean.parseBoolean(openIDConnectConfigElem.getFirstChildWithName( @@ -4132,6 +4153,8 @@ private class ConfigElements { public static final String OPENID_CONNECT_USERINFO_JWT_SIGNATURE_ALGORITHM = "UserInfoJWTSignatureAlgorithm"; public static final String OPENID_CONNECT_USERINFO_MULTI_VALUE_SUPPORT_ENABLED = "UserInfoMultiValueSupportEnabled"; + public static final String OPENID_CONNECT_USERINFO_INTERNAL_PREFIXED_ROLE_CLAIM_ENABLED = + "UserInfoInternalPrefixedRolesClaimEnabled"; public static final String OPENID_CONNECT_SIGN_JWT_WITH_SP_KEY = "SignJWTWithSPKey"; public static final String OPENID_CONNECT_IDTOKEN_CUSTOM_CLAIM_CALLBACK_HANDLER = "IDTokenCustomClaimsCallBackHandler"; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java index 124e6baddd..1d2200fe1f 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java @@ -1,17 +1,19 @@ /* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2017-2025, WSO2 LLC. (http://www.wso2.com). * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. + * 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. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ package org.wso2.carbon.identity.openidconnect; @@ -35,6 +37,7 @@ import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.oauth.common.OAuthConstants; +import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dto.ScopeDTO; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; @@ -486,20 +489,36 @@ private void handleEmailVerifiedClaim(Map returnClaims) { } } - private void handleRolesClaim(Map returnClaims) { + public static void handleRolesClaim(Map returnClaims) { - if (returnClaims.containsKey(ROLES) && IdentityUtil.isGroupsVsRolesSeparationImprovementsEnabled() - && returnClaims.get(ROLES) instanceof String) { + if (!returnClaims.containsKey(ROLES) || !IdentityUtil.isGroupsVsRolesSeparationImprovementsEnabled()) { + return; + } + if (returnClaims.get(ROLES) instanceof String) { String multiAttributeSeparator = FrameworkUtils.getMultiAttributeSeparator(); List roles = Arrays.asList(returnClaims.get(ROLES).toString().split(multiAttributeSeparator)); for (String role : roles) { if (UserCoreConstants.INTERNAL_DOMAIN.equalsIgnoreCase(IdentityUtil.extractDomainFromName(role))) { - String domainRemovedRole = UserCoreUtil.removeDomainFromName(role); - roles.set(roles.indexOf(role), domainRemovedRole); + String domainRemovedRole = UserCoreUtil.removeDomainFromName(role); + roles.set(roles.indexOf(role), domainRemovedRole); } } returnClaims.put(ROLES, StringUtils.join(roles, multiAttributeSeparator)); + } else if (returnClaims.get(ROLES) instanceof String[]) { + // This check is added for the backward compatibility of userinfo response. + if (OAuthServerConfiguration.getInstance().getUserInfoInternalPrefixedRolesClaimEnabled()) { + return; + } + String[] roles = (String[]) returnClaims.get(ROLES); + for (int i = 0; i < roles.length; i++) { + String role = roles[i]; + if (UserCoreConstants.INTERNAL_DOMAIN.equalsIgnoreCase(IdentityUtil.extractDomainFromName(role))) { + String domainRemovedRole = UserCoreUtil.removeDomainFromName(role); + roles[i] = domainRemovedRole; + } + } + returnClaims.put(ROLES, roles); } }