Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve user info response to return roles without internal domain appended #2674

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -233,6 +233,8 @@ public class OAuthServerConfiguration {
private List<String> supportedIdTokenEncryptionMethods = new ArrayList<>();
private String userInfoJWTSignatureAlgorithm = "SHA256withRSA";
private boolean userInfoMultiValueSupportEnabled = true;
private boolean userInfoInternalPrefixedRolesClaimAllowed = true;

private String authContextTTL = "15L";
// property added to fix IDENTITY-4551 in backward compatible manner
private boolean useMultiValueSeparatorForAuthContextToken = true;
Expand Down Expand Up @@ -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 getUserInfoInternalPrefixedRolesClaimAllowed() {

return userInfoInternalPrefixedRolesClaimAllowed;
}

public String getConsumerDialectURI() {
return consumerDialectURI;
}
Expand Down Expand Up @@ -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_ALLOWED));
if (userInfoInternalPrefixedRolesClaim != null) {
userInfoInternalPrefixedRolesClaimAllowed =
Boolean.parseBoolean(userInfoInternalPrefixedRolesClaim.getText().trim());
}

if (openIDConnectConfigElem.getFirstChildWithName(
getQNameWithIdentityNS(ConfigElements.OPENID_CONNECT_SIGN_JWT_WITH_SP_KEY)) != null) {
isJWTSignedWithSPKey = Boolean.parseBoolean(openIDConnectConfigElem.getFirstChildWithName(
Expand Down Expand Up @@ -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_ALLOWED =
"UserInfoInternalPrefixedRolesClaimAllowed";
public static final String OPENID_CONNECT_SIGN_JWT_WITH_SP_KEY = "SignJWTWithSPKey";
public static final String OPENID_CONNECT_IDTOKEN_CUSTOM_CLAIM_CALLBACK_HANDLER =
"IDTokenCustomClaimsCallBackHandler";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
import org.wso2.carbon.identity.application.common.model.ServiceProvider;
import org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCache;
import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheEntry;
import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheKey;
import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException;
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
import org.wso2.carbon.identity.oauth.dao.OAuthAppDO;
import org.wso2.carbon.identity.oauth.user.UserInfoEndpointException;
import org.wso2.carbon.identity.oauth.user.UserInfoResponseBuilder;
Expand All @@ -40,6 +42,8 @@
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.identity.openidconnect.internal.OpenIDConnectServiceComponentHolder;
import org.wso2.carbon.identity.openidconnect.model.RequestedClaim;
import org.wso2.carbon.user.core.UserCoreConstants;
import org.wso2.carbon.user.core.util.UserCoreUtil;

import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -50,6 +54,7 @@
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OAuth20Params.USERINFO;
import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.ROLES;

/**
* Abstract user info response builder.
Expand All @@ -76,6 +81,9 @@ public String getResponseString(OAuth2TokenValidationResponseDTO tokenResponse)
Map<String, Object> userClaims = retrieveUserClaims(tokenResponse);
Map<String, Object> filteredUserClaims = filterOIDCClaims(tokenResponse, clientId, spTenantDomain, userClaims);

// Handle roles claim.
handleRolesClaim(filteredUserClaims);

// Handle subject claim.
String subjectClaim = getSubjectClaim(userClaims, clientId, spTenantDomain, tokenResponse);
subjectClaim = getOIDCSubjectClaim(clientId, spTenantDomain, subjectClaim);
Expand All @@ -84,6 +92,29 @@ public String getResponseString(OAuth2TokenValidationResponseDTO tokenResponse)
return buildResponse(tokenResponse, spTenantDomain, filteredUserClaims);
}

private void handleRolesClaim(Map<String, Object> filteredUserClaims) {

// This check is added for the backward compatibility of userinfo response.
if (OAuthServerConfiguration.getInstance().getUserInfoInternalPrefixedRolesClaimAllowed()) {
return;
}

if (!(filteredUserClaims.get(ROLES) instanceof String[])) {
return;
}
String[] roles = (String[]) filteredUserClaims.get(ROLES);
if (roles == null) {
return;
}
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;
}
}
}

private String getOIDCSubjectClaim(String clientId, String spTenantDomain, String subjectClaim)
throws UserInfoEndpointException {

Expand Down
Loading