wso2 / product-is

Welcome to the WSO2 Identity Server source code! For info on working with the WSO2 Identity Server repository and contributing code, click the link below.
http://wso2.github.io/
Apache License 2.0
727 stars 713 forks source link

Setting local claims through adaptive authentication doesn't work with callback functions inside step's `onFail` callback #20446

Open ThaminduDilshan opened 1 month ago

ThaminduDilshan commented 1 month ago

Describe the issue: We can use the following adaptive logic to permanently set a user claim.

user.localClaims["http://wso2.org/claims/test"] = "true";

In the latest snapshot build, if this function is used inside a callback function of some other adaptive function and if the whole logic is defined inside the onFail callback function of a step, the claim update doesn't work.

How to reproduce:

  1. Login to console
  2. Create a new attribute named test
  3. Configure an application for login with the following adaptive script.

    var user = null;
    var userId = "";
    var username = "";
    var password = "";
    
    var onLoginRequest = function (context) {
        executeStep(1, {
            onSuccess: function (context) {
                Log.info("Login successful.");
            },
            onFail: function (context) {
                Log.info("Login failed.");
    
                // Retrieve login identifier and password provided by the user.
                username = context.request.params.username[0];
                password = context.request.params.password[0];
    
                Log.info("External invocation initiated for the user: " + username);
    
                // Retrieve unique user object for the username.
                var claimMap = {};
                claimMap["http://wso2.org/claims/username"] = "PRIMARY/" + username;
                user = getUniqueUserWithClaimValues(claimMap, context);
    
                // Prepare the connection data.
                var url = "<url>";
    
                var authConfig = {
                    type: "clientCredential",
                    properties: {
                        consumerKey: "<consumer_key>",
                        consumerSecret: "<consumer_secret>",
                        tokenEndpoint: "<token_endpoint>"
                    }
                };
    
                var requestHeaders = {
                    "Accept": "application/json"
                };
    
                var requestPayload = {
                    id: userId
                };
    
                Log.info("Invoking the external endpoint.");
    
                // Invoke the external endpoint.
                httpPost(url, requestPayload, requestHeaders, authConfig, {
                    onSuccess: function (context, data) {
                        if (data !== null && data.message !== null) {
                            if (data.message === "Success") {
                                Log.info("External invocation success for the user: " + userId + ". Response Identifier: " + data.contextId + ".");
                                user.localClaims["http://wso2.org/claims/test"] = "invoked";
                            } else {
                                Log.info("External invocation failed for the user: " + userId + ". Message: " + data.message + ".");
                            }
                        } else {
                            Log.info("External invocation failed for the user: " + userId + ".");
                        }
                    },
                    onFail: function (context, data) {
                        Log.info("Error occurred while invoking the API.");
                    },
                    onTimeout: function (context, data) {
                        Log.info("Connection timed out while invoking the API.");
                    }
                });
            }
        });
    };

    Note: This script uses httpPost function to reproduce the issue. However any other function with callbacks can be used for this.

  4. Login to the application with a invalid password. If the script is working correctly, the claim should be set to invoked. However it doesn't work, but the log gets printed.

Expected behavior: user.localClaims should set the claim permanently.

Additional observations

ThaminduDilshan commented 1 month ago

Tested with #5242 snapshot build which doesn't have the graal engine updates. Issue is not reproducible in that pack. Therefore should be related to the Graal changes.

Related UI issue: https://github.com/wso2/product-is/issues/20448