diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/JITProvisioningPostAuthenticationHandler.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/JITProvisioningPostAuthenticationHandler.java index 8a9939ea241d..4e439ce7e3b7 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/JITProvisioningPostAuthenticationHandler.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/JITProvisioningPostAuthenticationHandler.java @@ -317,9 +317,23 @@ private PostAuthnHandlerFlowStatus handleRequestFlow(HttpServletRequest request, localClaimValues = new HashMap<>(); } + String externalSubject = stepConfig.getAuthenticatedUser().getAuthenticatedSubjectIdentifier(); + if (FrameworkUtils.isConfiguredIdpSubForFederatedUserAssociationEnabled()) { + String userIdClaimURI = FrameworkUtils.getUserIdClaimURI(stepConfig.getAuthenticatedIdP(), + context.getTenantDomain()); + if (StringUtils.isNotEmpty(userIdClaimURI)) { + externalSubject = stepConfig.getAuthenticatedUser().getUserAttributes().entrySet().stream() + .filter(userAttribute -> userAttribute.getKey().getRemoteClaim().getClaimUri() + .equals(userIdClaimURI)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); + } + } + String associatedLocalUser = getLocalUserAssociatedForFederatedIdentifier(stepConfig.getAuthenticatedIdP(), - stepConfig.getAuthenticatedUser().getAuthenticatedSubjectIdentifier(), + externalSubject, context.getTenantDomain()); boolean isUserAllowsToLoginIdp = Boolean.parseBoolean(IdentityUtil .getProperty(ALLOW_LOGIN_TO_IDP)); @@ -356,8 +370,7 @@ private PostAuthnHandlerFlowStatus handleRequestFlow(HttpServletRequest request, FrameworkUtils.getFederatedAssociationManager() .createFederatedAssociation(new User(user), stepConfig.getAuthenticatedIdP(), - stepConfig.getAuthenticatedUser() - .getAuthenticatedSubjectIdentifier()); + externalSubject); associatedLocalUser = user.getDomainQualifiedUsername(); } } catch (UserStoreException e) { @@ -830,8 +843,21 @@ private void callDefaultProvisioningHandler(String username, AuthenticationConte } } - localClaimValues.put(FrameworkConstants.ASSOCIATED_ID, - stepConfig.getAuthenticatedUser().getAuthenticatedSubjectIdentifier()); + String externalSubject = stepConfig.getAuthenticatedUser().getAuthenticatedSubjectIdentifier(); + if (FrameworkUtils.isConfiguredIdpSubForFederatedUserAssociationEnabled()) { + String userIdClaimURI = FrameworkUtils.getUserIdClaimURI(stepConfig.getAuthenticatedIdP(), + context.getTenantDomain()); + if (StringUtils.isNotEmpty(userIdClaimURI)) { + externalSubject = stepConfig.getAuthenticatedUser().getUserAttributes().entrySet().stream() + .filter(userAttribute -> userAttribute.getKey().getRemoteClaim().getClaimUri() + .equals(userIdClaimURI)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); + } + } + + localClaimValues.put(FrameworkConstants.ASSOCIATED_ID, externalSubject); localClaimValues.put(FrameworkConstants.IDP_ID, stepConfig.getAuthenticatedIdP()); /* @@ -959,8 +985,20 @@ private void callDefaultProvisioningHandler(String username, AuthenticationConte private void handleConsents(HttpServletRequest request, StepConfig stepConfig, String tenantDomain) throws PostAuthenticationFailedException { + String externalSubject = stepConfig.getAuthenticatedUser().getAuthenticatedSubjectIdentifier(); + if (FrameworkUtils.isConfiguredIdpSubForFederatedUserAssociationEnabled()) { + String userIdClaimURI = FrameworkUtils.getUserIdClaimURI(stepConfig.getAuthenticatedIdP(), tenantDomain); + if (StringUtils.isNotEmpty(userIdClaimURI)) { + externalSubject = stepConfig.getAuthenticatedUser().getUserAttributes().entrySet().stream() + .filter(userAttribute -> userAttribute.getKey().getRemoteClaim().getClaimUri() + .equals(userIdClaimURI)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); + } + } String userName = getLocalUserAssociatedForFederatedIdentifier(stepConfig.getAuthenticatedIdP(), - stepConfig.getAuthenticatedUser().getAuthenticatedSubjectIdentifier(), tenantDomain); + externalSubject, tenantDomain); String consent = request.getParameter("consent"); String policyURL = request.getParameter("policy"); if (StringUtils.isNotEmpty(consent)) { diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/PostAuthAssociationHandler.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/PostAuthAssociationHandler.java index ce831f298fd2..1298ab0be1c7 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/PostAuthAssociationHandler.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/PostAuthAssociationHandler.java @@ -200,6 +200,19 @@ private String getUserNameAssociatedWith(AuthenticationContext context, StepConf String associatesUserName; String originalExternalIdpSubjectValueForThisStep = stepConfig.getAuthenticatedUser() .getAuthenticatedSubjectIdentifier(); + if (FrameworkUtils.isConfiguredIdpSubForFederatedUserAssociationEnabled()) { + String userIdClaimURI = FrameworkUtils.getUserIdClaimURI(stepConfig.getAuthenticatedIdP(), + context.getTenantDomain()); + if (StringUtils.isNotEmpty(userIdClaimURI)) { + originalExternalIdpSubjectValueForThisStep = stepConfig.getAuthenticatedUser().getUserAttributes() + .entrySet().stream() + .filter(userAttribute -> userAttribute.getKey().getRemoteClaim().getClaimUri() + .equals(userIdClaimURI)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); + } + } try { FrameworkUtils.startTenantFlow(context.getTenantDomain()); FederatedAssociationManager federatedAssociationManager = FrameworkUtils.getFederatedAssociationManager(); diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java index 5532f7bb547e..4422946e8269 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java @@ -143,6 +143,8 @@ public abstract class FrameworkConstants { public static final String IDP_RESOURCE_ID = "IDPResourceID"; public static final String ENABLE_JIT_PROVISION_ENHANCE_FEATURE = "JITProvisioning.EnableEnhancedFeature"; public static final String ERROR_CODE_INVALID_ATTRIBUTE_UPDATE = "SUO-10000"; + public static final String ENABLE_CONFIGURED_IDP_SUB_FOR_FEDERATED_USER_ASSOCIATION + = "JITProvisioning.EnableConfiguredIdpSubForFederatedUserAssociation"; // Error details sent from authenticators public static final String AUTH_ERROR_CODE = "AuthErrorCode"; diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java index dab6d72c0fea..539b08179bf3 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java @@ -107,6 +107,7 @@ import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticationResult; import org.wso2.carbon.identity.application.authentication.framework.store.UserSessionStore; import org.wso2.carbon.identity.application.common.model.Claim; +import org.wso2.carbon.identity.application.common.model.ClaimConfig; import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.application.common.model.FederatedAuthenticatorConfig; import org.wso2.carbon.identity.application.common.model.IdPGroup; @@ -205,12 +206,14 @@ import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.Config.AUTHENTICATION_CONTEXT_EXPIRY_VALIDATION; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.Config.SKIP_LOCAL_USER_SEARCH_FOR_AUTHENTICATION_FLOW_HANDLERS; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.Config.USER_SESSION_MAPPING_ENABLED; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ENABLE_CONFIGURED_IDP_SUB_FOR_FEDERATED_USER_ASSOCIATION; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.InternalRoleDomains.APPLICATION_DOMAIN; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.InternalRoleDomains.WORKFLOW_DOMAIN; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.REQUEST_PARAM_SP; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.CORRELATION_ID; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.IS_IDF_INITIATED_FROM_AUTHENTICATOR; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.USER_TENANT_DOMAIN_HINT; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.USERNAME_CLAIM; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.USE_IDP_ROLE_CLAIM_AS_IDP_GROUP_CLAIM; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_GETTING_IDP_BY_NAME; import static org.wso2.carbon.identity.configuration.mgt.core.constant.ConfigurationConstants.ErrorMessages.ERROR_CODE_ATTRIBUTE_DOES_NOT_EXISTS; @@ -799,6 +802,58 @@ public static Optional getApplicationResourceId(AuthenticationContext co .map(ServiceProvider::getApplicationResourceId); } + /** + * Retrieve the user id claim configured for the federated IDP. + * + * @param federatedIdpName Federated IDP name. + * @param tenantDomain Tenant domain. + * @return User ID claim configured for the IDP. + * @throws PostAuthenticationFailedException PostAuthenticationFailedException. + */ + public static String getUserIdClaimURI(String federatedIdpName, String tenantDomain) + throws PostAuthenticationFailedException { + String userIdClaimURI; + IdentityProvider idp; + try { + idp = FrameworkServiceDataHolder.getInstance().getIdentityProviderManager() + .getIdPByName(federatedIdpName, tenantDomain); + } catch (IdentityProviderManagementException e) { + throw new PostAuthenticationFailedException( + ERROR_WHILE_GETTING_IDP_BY_NAME.getCode(), + String.format(FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_GETTING_IDP_BY_NAME.getMessage(), + tenantDomain), e); + } + if (idp == null) { + return null; + } + ClaimConfig claimConfigs = idp.getClaimConfig(); + if (claimConfigs == null) { + return null; + } + ClaimMapping[] claimMappings = claimConfigs.getClaimMappings(); + if (claimMappings == null || claimMappings.length < 1) { + return null; + } + userIdClaimURI = claimConfigs.getUserClaimURI(); + if (userIdClaimURI != null) { + return userIdClaimURI; + } + ClaimMapping userNameClaimMapping = Arrays.stream(claimMappings).filter(claimMapping -> + StringUtils.equals(USERNAME_CLAIM, claimMapping.getLocalClaim().getClaimUri())) + .findFirst() + .orElse(null); + if (userNameClaimMapping != null) { + userIdClaimURI = userNameClaimMapping.getRemoteClaim().getClaimUri(); + } + return userIdClaimURI; + } + + + public static boolean isConfiguredIdpSubForFederatedUserAssociationEnabled() { + + return Boolean.parseBoolean(IdentityUtil.getProperty(ENABLE_CONFIGURED_IDP_SUB_FOR_FEDERATED_USER_ASSOCIATION)); + } + private static String getServiceProviderNameByReferer(HttpServletRequest request) { String serviceProviderName = null; @@ -2745,7 +2800,7 @@ public static String getMappedIdpRoleClaimUri(String idpRoleClaimUri, StepConfig } // check for role claim uri in the idaps dialect. for (Entry entry : carbonToStandardClaimMapping.entrySet()) { - if (StringUtils.isNotEmpty(idpRoleMappingURI) && + if (StringUtils.isNotEmpty(idpRoleMappingURI) && idpRoleMappingURI.equalsIgnoreCase(entry.getValue())) { idpRoleMappingURI = entry.getKey(); } diff --git a/features/authentication-framework/org.wso2.carbon.identity.application.authentication.framework.server.feature/resources/org.wso2.carbon.identity.application.authentication.framework.server.feature.default.json b/features/authentication-framework/org.wso2.carbon.identity.application.authentication.framework.server.feature/resources/org.wso2.carbon.identity.application.authentication.framework.server.feature.default.json index 5a1788816a67..a453c7250a6b 100644 --- a/features/authentication-framework/org.wso2.carbon.identity.application.authentication.framework.server.feature/resources/org.wso2.carbon.identity.application.authentication.framework.server.feature.default.json +++ b/features/authentication-framework/org.wso2.carbon.identity.application.authentication.framework.server.feature/resources/org.wso2.carbon.identity.application.authentication.framework.server.feature.default.json @@ -263,5 +263,6 @@ "console", "SYSTEM" ], - "authentication.jit_provisioning.associating_to_existing_user": false + "authentication.jit_provisioning.associating_to_existing_user": false, + "authentication.jit_provisioning.enable_configured_idp_sub_for_federated_user_association": false } diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 index 9b3d9becafaf..2c2b69a74762 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 @@ -1122,7 +1122,7 @@ 0 {{oauth.token_generation.retry_count_on_persistence_failures}} - +