Dynamic Display of Groups in Catalog Item - Microsoft Entra ID Spoke OAuth

JayAdmin_16
Mega Sage

Hi there, I'm having a bit of trouble dynamically retrieving AD groups in a catalog item variable through the Microsoft Entra ID Spoke OAuth. As part of the solution for the business, we want to perform this function through a Script Include. 

Currently the error we see in the logs is: API response: null. Afterwards we can see it attempts to make a HTTPRequest: Starting _makeHttpRequest function and then stops. 

Here is the Script Include (with sensitive information taken out): 

var AzureADIntegration = Class.create();
AzureADIntegration.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    // Function to retrieve groups from Azure AD
    getAzureADGroups: function() {
        gs.info('Starting getAzureADGroups function');

        // Retrieve the token from the Application Registry
        var token = this._getTokenFromRegistry();
        gs.info('Using token from Application Registry: ' + token);

        // Make the API call to Azure AD to fetch groups
        var url = 'https://graph.microsoft.com/v1.0/groups';
        var headers = {
            'Authorization': 'Bearer ' + token
        };
        
        gs.info('Making API call to Azure AD to fetch groups');
        var response = this._makeHttpRequest(url, 'GET', headers);
        gs.info('API response: ' + response);
        
        return response;
    },

    // Function to make an HTTP request
    _makeHttpRequest: function(url, method, headers) {
        gs.info('Starting _makeHttpRequest function');
        
        var request = new GlideHTTPClient();
        var response = request.send(url, method, '', headers);
        
        gs.info('HTTP request sent. Status code: ' + response.getStatusCode());
        
        if (response.getStatusCode() == 200) {
            gs.info('Request successful. Response body: ' + response.getBody());
            return response.getBody();
        } else {
            gs.error('Request failed. Status code: ' + response.getStatusCode());
            return null;
        }
    },

    // Function to get token from Application Registry
    _getTokenFromRegistry: function() {
        gs.info('Starting _getTokenFromRegistry function');
        
        var gr = new GlideRecord('oauth_credential');
        gr.addQuery('name', 'Your Application Registry Name'); // Replace with your Application Registry name
        gr.query();
        if (gr.next()) {
            gs.info('Token found in Application Registry');
            return gr.token_received;
        }
        gs.error('No token found in Application Registry');
        return null;
    },

    type: 'AzureADIntegration'
});


Here is the catalog Client Script (with sensitive information taken out): 

function onLoad() {
    // Define the function to get Azure AD Groups
    var ga = new GlideAjax('AzureADIntegration');  // Name of the Script Include AzureADIntegration
    ga.addParam('sysparm_name', 'getAzureADGroups');  // The function to call in Script Include
    ga.getXMLAnswer(function(response) {
        var result = response.responseXML.documentElement.getAttribute("answer");
        
        // Log the raw result for debugging
        console.log('Response from GlideAjax:', result);

        if (result) {
            try {
                var groups = JSON.parse(result);  // Assuming response is in JSON format

                // Log the groups array for debugging
                console.log('Parsed groups:', groups);

                // Assuming we want to populate the dropdown with group names
                var dropdown = g_form.getControl('azure_ad_groups');  // Get the dropdown element by variable name
                dropdown.options.length = 0;  // Clear any existing options

                // Add a default option
                var defaultOption = new Option('Select an Azure AD group', '');
                dropdown.add(defaultOption);

                // Populate the dropdown with the group names
                groups.value.forEach(function(group) {
                    var option = new Option(group.displayName);  // Add group name
                    dropdown.add(option);
                });

            } catch (error) {
                console.error('Error parsing Azure AD groups:', error);
                // Handle parsing errors
                var dropdown = g_form.getControl('azure_ad_groups');
                dropdown.options.length = 0;
                var errorOption = new Option('Error loading groups', '');
                dropdown.add(errorOption);
            }
        } else {
            // Handle the case where no result was returned
            console.warn('No result received from GlideAjax call');
            var dropdown = g_form.getControl('azure_ad_groups');
            dropdown.options.length = 0;
        }
    });
}


I'm very new to all this, so any gentle and detailed advice would be greatly appreciated.

1 ACCEPTED SOLUTION

JayAdmin_16
Mega Sage

A solution has been found. Just in case anyone faces the same issues I did, here's the coding solution: 

Script Include: (Replace all "<...>" with actual values)

var <SCRIPT INCLUDE> = Class.create();
<SCRIPT NCLUDE>.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    // Function to retrieve groups from Azure AD
    getADGroups: function() {
        gs.info('Starting getADGroups function');

        // Retrieve the token from the Application Registry
        var token = this._getTokenFromRegistry();
        if (!token) {
            gs.error('Failed to retrieve token from Application Registry');
            return null;
        }
        gs.info('Using token from Application Registry');

        // Make the API call to Azure AD to fetch groups
        try {
            var r = new sn_ws.RESTMessageV2('<REST MESSAGE NAME>', 'Default GET');
            var response = r.execute();
            var responseBody = response.getBody();
            var httpStatus = response.getStatusCode();

            gs.info('API response received with status code: ' + httpStatus);
            gs.info('Raw response body: ' + responseBody); // Log the raw response

         // Directly parse the response body to get group names
            var groupNames = JSON.parse(responseBody).value.map(function(group) {
                return group.displayName;
            });

            // Log the group names
            gs.info('Group names: ' + JSON.stringify(groupNames));

            // Return the array of group names as a JSON string
            return JSON.stringify(groupNames);  // This ensures it's properly escaped for JSON
        } catch (ex) {
            var message = ex.message;
            gs.error('API call failed: ' + message);
            return 'API call failed: ' + message;
        }
    },

    // Function to get OAuth2 token
    _getOAuthToken: function(url, client_id, client_secret) {
        gs.info('Starting _getOAuthToken function');
        
        var requestBody = 'client_id=' + client_id + '&client_secret=' + client_secret + '<OAUTH 2.0 CLIENT CREDENTIALS GRANT FLOW>';
        var request = new GlideHTTPRequest(url);
        request.setRequestBody(requestBody);
        request.setMethod('POST');
        
        var response = request.execute();
        gs.info('Token request sent. Status code: ' + response.getStatusCode());
        
        if (response.getStatusCode() == 200) {
            gs.info('Token request successful. Response body: ' + response.getBody());
            return response.getBody();
        }
        
        gs.error('Token request failed. Status code: ' + response.getStatusCode());
        return null;
    },

    // Function to get token from Application Registry
    _getTokenFromRegistry: function() {
        gs.info('Starting _getTokenFromRegistry function');
        
        var gr = new GlideRecord('oauth_credential');
        gr.addQuery('sys_id', '<YOUR APPLICATION REGISTRY ID>'); // Replace with your Application Registry name
        gr.query();
        if (gr.next()) {
            gs.info('Token found in Application Registry');
            return gr.token_received;
        }
        gs.error('No token found in Application Registry');
        return null; // Added return statement to handle case where no record is found
    },

    type: '<SCRIPT INCLUDE>'
});

 
And the Catalog Client Script: 

function onLoad() {
    // Define the function to get Azure AD Groups
    var ga = new GlideAjax('<SCRIPT INCLUDE>'); // Name of the Script Include
    ga.addParam('sysparm_name', 'getAzureAD'); // The function to call in Script Include
    ga.getXML(triggerCallBack);
    
    function triggerCallBack(response) {
        var result = response.responseXML.documentElement.getAttribute("answer");
        alert('Result from GlideAjax: ' + result);  // Log the raw result for debugging
        console.log('Result from GlideAjax:', result);

        if (result) {
            try {
                var responseBody = JSON.parse(result); // Parse the JSON response from the Script Include
                
                if (responseBody.length > 0) {
                    // If we have groups, populate them into the dropdown
                    for (var i = 0; i < responseBody.length; i++) {
                        g_form.addOption("<CATALOG VARIABLE>", responseBody[i], responseBody[i], i);
                    }
                } else {
                    g_form.addOption("<CATALOG VARIABLE>", "Error", "No groups found");
                    alert('No groups found');
                }
            } catch (e) {
                alert('Error parsing JSON: ' + e.message);  // Catch parsing errors
                console.error('Error parsing JSON:', e);
            }
        } else {
            g_form.addOption("<CATALOG VARIABLE>", "Error", "Could not populate groups");
            alert('No groups found or returned from GlideAjax call.');
            console.error('No groups found or returned from GlideAjax call.');
        }
    }
}

 

View solution in original post

2 REPLIES 2

Shivalika
Mega Sage

Hello @JayAdmin_16 

 

In the getTokenFromRegistry - you have used token_received - is it a valid field in Oauth application registry ? Have you removed some lines here ? 

 

Have you added logs in this and checked where is the script actually breaking ? 

 

Kindly mark my answer as helpful and accept solution if it helped you in anyway,

 

Regards,

Shivalika 

 

My LinkedIn - https://www.linkedin.com/in/shivalika-gupta-540346194

 

My youtube - https://youtube.com/playlist?list=PLsHuNzTdkE5Cn4PyS7HdV0Vg8JsfdgQlA&si=0WynLcOwN

eEISQCY

JayAdmin_16
Mega Sage

A solution has been found. Just in case anyone faces the same issues I did, here's the coding solution: 

Script Include: (Replace all "<...>" with actual values)

var <SCRIPT INCLUDE> = Class.create();
<SCRIPT NCLUDE>.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    // Function to retrieve groups from Azure AD
    getADGroups: function() {
        gs.info('Starting getADGroups function');

        // Retrieve the token from the Application Registry
        var token = this._getTokenFromRegistry();
        if (!token) {
            gs.error('Failed to retrieve token from Application Registry');
            return null;
        }
        gs.info('Using token from Application Registry');

        // Make the API call to Azure AD to fetch groups
        try {
            var r = new sn_ws.RESTMessageV2('<REST MESSAGE NAME>', 'Default GET');
            var response = r.execute();
            var responseBody = response.getBody();
            var httpStatus = response.getStatusCode();

            gs.info('API response received with status code: ' + httpStatus);
            gs.info('Raw response body: ' + responseBody); // Log the raw response

         // Directly parse the response body to get group names
            var groupNames = JSON.parse(responseBody).value.map(function(group) {
                return group.displayName;
            });

            // Log the group names
            gs.info('Group names: ' + JSON.stringify(groupNames));

            // Return the array of group names as a JSON string
            return JSON.stringify(groupNames);  // This ensures it's properly escaped for JSON
        } catch (ex) {
            var message = ex.message;
            gs.error('API call failed: ' + message);
            return 'API call failed: ' + message;
        }
    },

    // Function to get OAuth2 token
    _getOAuthToken: function(url, client_id, client_secret) {
        gs.info('Starting _getOAuthToken function');
        
        var requestBody = 'client_id=' + client_id + '&client_secret=' + client_secret + '<OAUTH 2.0 CLIENT CREDENTIALS GRANT FLOW>';
        var request = new GlideHTTPRequest(url);
        request.setRequestBody(requestBody);
        request.setMethod('POST');
        
        var response = request.execute();
        gs.info('Token request sent. Status code: ' + response.getStatusCode());
        
        if (response.getStatusCode() == 200) {
            gs.info('Token request successful. Response body: ' + response.getBody());
            return response.getBody();
        }
        
        gs.error('Token request failed. Status code: ' + response.getStatusCode());
        return null;
    },

    // Function to get token from Application Registry
    _getTokenFromRegistry: function() {
        gs.info('Starting _getTokenFromRegistry function');
        
        var gr = new GlideRecord('oauth_credential');
        gr.addQuery('sys_id', '<YOUR APPLICATION REGISTRY ID>'); // Replace with your Application Registry name
        gr.query();
        if (gr.next()) {
            gs.info('Token found in Application Registry');
            return gr.token_received;
        }
        gs.error('No token found in Application Registry');
        return null; // Added return statement to handle case where no record is found
    },

    type: '<SCRIPT INCLUDE>'
});

 
And the Catalog Client Script: 

function onLoad() {
    // Define the function to get Azure AD Groups
    var ga = new GlideAjax('<SCRIPT INCLUDE>'); // Name of the Script Include
    ga.addParam('sysparm_name', 'getAzureAD'); // The function to call in Script Include
    ga.getXML(triggerCallBack);
    
    function triggerCallBack(response) {
        var result = response.responseXML.documentElement.getAttribute("answer");
        alert('Result from GlideAjax: ' + result);  // Log the raw result for debugging
        console.log('Result from GlideAjax:', result);

        if (result) {
            try {
                var responseBody = JSON.parse(result); // Parse the JSON response from the Script Include
                
                if (responseBody.length > 0) {
                    // If we have groups, populate them into the dropdown
                    for (var i = 0; i < responseBody.length; i++) {
                        g_form.addOption("<CATALOG VARIABLE>", responseBody[i], responseBody[i], i);
                    }
                } else {
                    g_form.addOption("<CATALOG VARIABLE>", "Error", "No groups found");
                    alert('No groups found');
                }
            } catch (e) {
                alert('Error parsing JSON: ' + e.message);  // Catch parsing errors
                console.error('Error parsing JSON:', e);
            }
        } else {
            g_form.addOption("<CATALOG VARIABLE>", "Error", "Could not populate groups");
            alert('No groups found or returned from GlideAjax call.');
            console.error('No groups found or returned from GlideAjax call.');
        }
    }
}