Skip to content

[IS 7.2.0] Organisation Discovery Flow - EmailDomainValidationHandler Doesn't Null-check localClaimValues, Crashes when Adaptive Script Calls fail() #28174

Description

@vaibhavhapani

Description

During the organization discovery login flow, if fail() is called from a conditional authentication script, EmailDomainValidationHandler [1] crashes with a NullPointerException instead of letting the script's failure propagate cleanly.

Root cause: EmailDomainValidationHandler.handle() reads the federated user's email claim from context.getProperty(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES) [2]. This property is only populated on the success path (as part of JIT provisioning/claim mapping). When the conditional authentication script calls fail() inside a step's onSuccess callback, the sequence is marked as failed, and the handler responsible for populating UNFILTERED_LOCAL_CLAIM_VALUES skips its work; reasonably, since there's no need to provision/map claims for a user who is being denied.

However, EmailDomainValidationHandler still executes unconditionally as a registered post-authentication handler, with no check for a failed sequence and no null check on the returned map. It calls localClaimValues.get(FrameworkConstants.EMAIL_ADDRESS_CLAIM) directly, and since localClaimValues itself is null (not just missing the email key), this throws:

java.lang.NullPointerException: Cannot invoke "java.util.Map.get(Object)" because "localClaimValues" is null
	at org.wso2.carbon.identity.organization.discovery.service.listener.EmailDomainValidationHandler.handle(EmailDomainValidationHandler.java:159)
	at org.wso2.carbon.identity.application.authentication.framework.services.PostAuthenticationMgtService.executePostAuthnHandler(PostAuthenticationMgtService.java:119)
	at org.wso2.carbon.identity.application.authentication.framework.services.PostAuthenticationMgtService.handlePostAuthentication(PostAuthenticationMgtService.java:85)

After removing the conditional authentication script, the sequence completes successfully, UNFILTERED_LOCAL_CLAIM_VALUES is present in the context's properties, localClaimValues resolves to the email address correctly, and the flow completes without error.

User-facing impact: the user never sees the script's intended access_denied / "Access not allowed" message. Instead they land on the generic retry.do error page ("Authentication Error! Something went wrong during the authentication process. Please try signing in again."), which is misleading; it looks like a broken login rather than an intentional access denial.

[1] - https://github.com/wso2-extensions/identity-organization-management/blob/main/components/org.wso2.carbon.identity.organization.discovery.service/src/main/java/org/wso2/carbon/identity/organization/discovery/service/listener/EmailDomainValidationHandler.java
[2] - https://github.com/wso2-extensions/identity-organization-management/blob/4c62c9e0356e4ccfca607554de544a69ac6c2e86/components/org.wso2.carbon.identity.organization.discovery.service/src/main/java/org/wso2/carbon/identity/organization/discovery/service/listener/EmailDomainValidationHandler.java#L148

Affected Component

org.wso2.carbon.identity.organization.discovery.service

Steps to Reproduce

  1. Add the following to deployment.toml to allow conditional authentication scripts for applications in a sub-organization, then start the server:
    [authentication.adaptive.shared_applications] enable=true
  2. Create an application and a sub-organization at the root level, and share the application with the sub-organization.
  3. Enable Organization Discovery and map a domain (e.g. abc.com) to that sub-organization.
  4. Switch to the sub-organization and create a connection to another IS instance (running on port 9444) as an identity provider.
  5. In the IS instance on 9444, create a user with an email as the username, using a domain that matches the one mapped in step 3 i.e. abc.com.
  6. Set this connection as the login option for step 1 of the application's sign-in flow.
  7. Also add the following conditional authentication script to the application at the sub-organization level:
    var onLoginRequest = function(context) {
        executeStep(1, {
            onSuccess: function(context) {
                var hasRole = hasAnyOfTheRolesV2(context, ['any role that is not assigned to the user']);
                if (!hasRole) {
                    fail({'errorCode': 'access_denied', 'errorMessage': 'Access not allowed.'});
                }
            }
        });
    };
  8. Attempt to log in to the registered application: click Sign in with SSO → enter the email → authenticate with that IdP → observe the error.

Please select the area issue is related to

Other

Version

IS 7.2.0

Environment Details (with versions)

No response

Developer Checklist

  • [Behavioural Change] Does this change introduce a behavioral change to the product?
  •  ↳ Approved by team lead
  •  ↳ Label impact/behavioral-change added
  • [Migration Impact] Does this change have a migration impact?
  •  ↳ Migration label added (e.g., 7.2.0-migration)
  •  ↳ Migration issues created and linked
  • [New Configuration] Does this change introduce a new configuration?
  •  ↳ Label config added
  •  ↳ Configuration is properly documented

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions