Santosh Sahoo, Author at ServiceNow Guru https://servicenowguru.com/author/santoshsahoo/ ServiceNow Consulting Scripting Administration Development Tue, 22 Oct 2024 15:56:11 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.2 https://servicenowguru.com/wp-content/uploads/2024/05/cropped-SNGuru-Icon-32x32.png Santosh Sahoo, Author at ServiceNow Guru https://servicenowguru.com/author/santoshsahoo/ 32 32 QR Code-Based Incident Creation from URL Parameters https://servicenowguru.com/client-scripts-scripting/qr-code-based-incident-creation-from-url-parameters/ Tue, 22 Oct 2024 15:56:11 +0000 https://servicenowguru.com/?p=17135 Imagine you could report issues with just a quick scan of a QR code. In this article, I'll show you how to set up a system in ServiceNow that lets users scan QR codes to create incident reports. This method makes it easy to report problems with meeting rooms, printers, or any other equipment in your

The post QR Code-Based Incident Creation from URL Parameters appeared first on ServiceNow Guru.

]]>
Imagine you could report issues with just a quick scan of a QR code. In this article, I’ll show you how to set up a system in ServiceNow that lets users scan QR codes to create incident reports. This method makes it easy to report problems with meeting rooms, printers, or any other equipment in your office.

Use Case: Reporting Incidents with QR Codes

Let’s start with the use case. Picture QR codes placed in various locations like meeting rooms, printers, or other office equipment. These QR codes contain URLs with parameters that correspond to the sys_id of the Configuration Item (CI) or asset in the ServiceNow CMDB. When a user scans the QR code, it directs them to an Incident Record Producer with important fields such as LocationAsset Information already filled in. This links the reported issue directly to the correct asset and location, allowing the helpdesk team to quickly identify and resolve the problem, while freeing the user from having to manually enter all the details.

Technical Solution: Catalog Client Script for Parsing URL Parameters

To make this work, we need a catalog client script that reads the URL parameters and maps them to variables with the same name as the “key” in the URL. Here’s the script:

Catalog Client Script

/**
 * Populates catalog variable fields with values from URL parameters.
 * @function
 * @throws {Error} Throws an error if an unexpected situation occurs.
 */
function onLoad() {
    try {
        /** Get the parameters from the URL */
        var _window = window ? window : this.window;
        var urlParams = new URLSearchParams(_window.location.search);

        /** Iterate over each parameter in the URL */
        urlParams.forEach(function(value, key) {
            try {
                /** Check if a variable with the same name exists in the catalog form */
                var variable = g_form.getControl(key);
                if (variable) {
                    /** Set the value in the catalog variable field */
                    g_form.setValue(key, value);
                }
            } catch (innerError) {
                /** Handle errors that occur during iteration */
                console.error('Error during parameter iteration:', innerError);
            }
        });
    } catch (error) {
        /** Handle errors that occur during the main execution */
        console.error('An unexpected error occurred:', error);
        /** You may choose to throw the error again or handle it differently based on your requirements. */
    }
}

How the Script Works

  1. Get the Parameters from the URL: The script starts by checking if the window object is available. It then creates a URLSearchParams object from the URL’s query string, which allows easy access to the URL parameters.
  2. Iterate Over Each Parameter: The script uses the forEach method to iterate over each key-value pair in the URL parameters.
  3. Check for Matching Variables: For each parameter, the script checks if there is a corresponding variable in the catalog form with the same name as the key. It does this using the g_form.getControl(key) method.
  4. Set the Variable Value: If a matching variable is found, the script sets its value to the corresponding value from the URL parameter using the g_form.setValue(key, value) method.
  5. Error Handling: The script includes error handling to catch and log any errors that occur during the main execution or the iteration over parameters. This ensures that any issues are logged for debugging purposes.

Implementation Steps

Here’s how you can set up the QR code solution:

  1. Create a Variable Set: Go to Service Catalog > Catalog Variables > Variable Sets and create a new variable set. Name it something generic and understandable, such as “URLParameterMapper” or “URLVariableBinder,” following your organization’s naming conventions. Add the catalog client script provided above to this variable set.
  2. Generate QR Codes: Create QR codes that encode URLs pointing to the Incident Record Producer. Make sure the URLs include parameters for the CI/asset sys_id.
  3. Create Record Producers or Catalog Items: Set up record producers or catalog items with their own variables or variable sets. Either match the variable names to the keys in the URL parameters, or create the QR code URL so that the keys match the variable names in the record producer. Otherwise, the variables won’t map correctly and won’t populate from the URL.
  4. Add the Variable Set: Add the variable set from step 1 to the record producers or catalog items created in step 3.

Conclusion

By following these steps, users can easily raise incidents by scanning QR codes, with the incident form pre-filled with relevant information from the URL parameters. This streamlines the process of incident creation and ensures accurate reporting of issues related to specific CIs or assets.

The post QR Code-Based Incident Creation from URL Parameters appeared first on ServiceNow Guru.

]]>
ServiceNow Checklist Automation: Simplifying Catalog Task Management https://servicenowguru.com/scripting/servicenow-checklist-automation-simplifying-catalog-task-management/ https://servicenowguru.com/scripting/servicenow-checklist-automation-simplifying-catalog-task-management/#comments Wed, 02 Oct 2024 10:00:08 +0000 https://servicenowguru.com/?p=15533 Automating checklist creation for tasks in ServiceNow can save significant time and ensure consistency across your IT processes. This guide will show you how to implement this using a Script Include, Business Rule (or Flow Designer), and System Properties. You will use the checklist and checklist_item tables to automatically create and manage checklists for catalog tasks. The system property stores checklist configurations in

The post ServiceNow Checklist Automation: Simplifying Catalog Task Management appeared first on ServiceNow Guru.

]]>
Automating checklist creation for tasks in ServiceNow can save significant time and ensure consistency across your IT processes. This guide will show you how to implement this using a Script IncludeBusiness Rule (or Flow Designer), and System Properties.

You will use the checklist and checklist_item tables to automatically create and manage checklists for catalog tasks. The system property stores checklist configurations in a JSON format, allowing you to customize checklist items and define their mandatory status for different catalog items.

If you need to manage a large number of checklists, you can create a custom table in your scoped application to store the configurations. A custom table will help you manage the data more easily and offer better flexibility for future updates. In this case, you will need to modify the Script Include to retrieve checklist data from the new table instead of the system property.

The automation is triggered by a Business Rule in the Global Scope, which ensures that tasks cannot be closed unless all mandatory checklist items are completed. By automating this process, you can maintain consistency and reduce manual work, especially in IT service management workflows.

Key Components

System Property

The system property, catalogTask.checklists, stores the configuration for the checklists. This property uses a JSON structure to define which checklists and items are associated with specific catalog items. Each catalog item in the configuration includes the following:

  • Country or Catalog: You can group the checklist by Catalog or Country at the highest level.
  • Catalog Item Sys ID: Each catalog item is linked to specific service request tasks, and each task can have its own checklist.
  • Checklist Name: The name of the checklist associated with the catalog item.
  • Items: A list of individual checklist items, where each item includes:
    • name: The name of the checklist item.
    • order: The display order of the checklist item.
    • mandatory: A boolean that determines whether the item must be completed before the task can be closed.

If you are handling many checklists, using a custom table within your scoped application will scale better. The custom table can store the checklist data, and you can modify the Script Include to pull data from that table instead of the system property.

Checklist and Checklist Item Tables

The checklist and checklist_item tables store the checklists and their items for each catalog task. When you create a task, the Business Rule checks the system property to determine if a checklist is required. If the checklist data exists, the script inserts records into the checklist table and adds individual items to the checklist_item table.

The checklist table links the checklist to the specific catalog task using the document field. The checklist_item table stores each checklist item with details such as the name, order, and completed status. The complete field tracks whether each item has been completed.

You can also use the Checklist Template as an alternative, provided that your governance structure allows for easy management of these configurations in production environments. This approach may simplify the process, especially if you’re looking to manage checklist setups more efficiently.

Business Rule in Global Scope

The Business Rule triggers the checklist creation process when you create a new catalog task and validates the checklist completion when the task is updated. The rule queries the checklist and checklist_item tables to make sure that all mandatory items are complete before allowing the task to close.

The Business Rule needs to be in the Global Scope to use the setAbortAction(true) method, which prevents the task from closing if any mandatory checklist items are incomplete. You cannot use this method in scoped applications because they do not allow aborting database transactions directly.

System Property Configuration

Create a system property named catalogTask.checklists and store your JSON configuration defining the checklists and their items.

Example JSON:

{
  "checklists": {
    "<Country or Catalog>": {
      "sys_id_of_Item1": {
        "checklistName": {
          "items": [
            {
              "name": "Item1 Name1",
              "order": 1,
              "mandatory": true
            },
            {
              "name": "Item1 Name2",
              "order": 2,
              "mandatory": false
            },
            {
              "name": "Item1 Name3",
              "order": 3,
              "mandatory": true
            }
          ]
        }
      },
      "sys_id_of_Item2": {
        "checklistName": {
          "items": [
            {
              "name": "Item2 Name1",
              "order": 1,
              "mandatory": false
            },
            {
              "name": "Item2 Name2",
              "order": 2,
              "mandatory": true
            }
          ]
        }
      }
    }
  }
}

 

Script Include

The ChecklistCreator Script Include creates and manages checklists for catalog tasks. It retrieves the checklist configuration from the system property and determines whether to create a checklist for a specific catalog task.

When a checklist needs to be created, the script uses the catalog item sys_id to retrieve the relevant checklist data from the system property. If the data exists, the script automatically creates the checklist and its items for the task.

The system property defines which checklist items are mandatory. The script checks the actual items in the checklist_item table to ensure they are marked as complete. If all mandatory items are complete, the task proceeds. If not, the script blocks the task from closing and displays a message to the user.

Scoped Script Include Name: ChecklistCreator

var ChecklistCreator = Class.create();
ChecklistCreator.prototype = {
    initialize: function() {},

    /**
     * Retrieves the checklist data for a catalog item from the system property.
     * 
     * @param {String} catalogItemSysId - The sys_id of the catalog item.
     * @returns {Object|null} - Returns the checklist data as a JSON object if it exists, null otherwise.
     */
    getChecklistData: function(catalogItemSysId) {
        try {
            /* Get the JSON from the system property */
            var jsonString = gs.getProperty('x_916860_autocklst.catalogTask.checklists');
            if (!jsonString) {
                gs.error('System property x_916860_autocklst.catalogTask.checklists is not set or is empty');
                return null;
            }

            /* Parse the JSON string */
            var checklists;
            try {
                checklists = JSON.parse(jsonString);
            } catch (e) {
                gs.error('Failed to parse JSON from system property: ' + e.message);
                return null;
            }

            /* Retrieve the checklist data for the catalog item */
            for (var i = 0; i < checklists.length; i++) {
                if (checklists[i].catalog_item_sys_id === catalogItemSysId) {
                    return checklists[i];
                }
            }

            return null;
        } catch (e) {
            gs.error('Unexpected error occurred in getChecklistData: ' + e.message);
            return null;
        }
    },

    /**
     * Creates checklists and items for a catalog task based on the retrieved checklist data.
     * 
     * @param {String} catalogTaskSysId - The sys_id of the catalog task.
     * @param {Object} checklistData - The checklist data retrieved from the system property.
     */
    createChecklistsForCatalogTask: function(catalogTaskSysId, checklistData) {
        try {
            if (!checklistData) {
                gs.error('No checklist data provided for catalog task: ' + catalogTaskSysId);
                return;
            }

            var items = checklistData.items;
            if (!items) {
                gs.error('Checklist items not found for the specified catalog task and checklist name');
                return;
            }

            /* Check if a checklist already exists for the catalog task */
            var existingChecklistGR = new GlideRecord('checklist');
            existingChecklistGR.addQuery('document', catalogTaskSysId);
            existingChecklistGR.query();
            if (existingChecklistGR.next()) {
                gs.info('Checklist already exists for catalog task: ' + catalogTaskSysId);
                return;
            }

            /* Create checklist record */
            var checklistSysId;
            try {
                var checklistGR = new GlideRecord('checklist');
                checklistGR.initialize();
                checklistGR.document = catalogTaskSysId;
                checklistGR.name = checklistData.checklist_name;
                checklistGR.table = 'sc_task';
                checklistSysId = checklistGR.insert();
            } catch (e) {
                gs.error('Failed to create checklist record for catalog task: ' + e.message);
                return;
            }

            if (!checklistSysId) {
                gs.error('Failed to create checklist record for catalog task: ' + catalogTaskSysId);
                return;
            }

            /* Create checklist items */
            try {
                items.forEach(function(item) {
                    var checklistItemGR = new GlideRecord('checklist_item');
                    checklistItemGR.initialize();
                    checklistItemGR.checklist = checklistSysId;
                    checklistItemGR.name = item.name;
                    checklistItemGR.order = item.order;
                    checklistItemGR.mandatory = item.mandatory;
                    checklistItemGR.insert();
                });
            } catch (e) {
                gs.error('Failed to create checklist items: ' + e.message);
                return;
            }

            gs.info('Checklist and items created successfully for catalog task: ' + catalogTaskSysId);
        } catch (e) {
            gs.error('Unexpected error occurred in createChecklistsForCatalogTask: ' + e.message);
        }
    },

    /**
 * Checks if all mandatory checklist items are checked for a given catalog task.
 * 
 * @param {String} catalogTaskSysId - The sys_id of the catalog task.
 * @param {String} checklistSysId - The sys_id of the checklist.
 * @returns {Boolean} - Returns true if all mandatory checklist items are completed, false otherwise.
 */
areMandatoryChecklistItemsChecked: function(catalogTaskSysId, checklistSysId) {
    try {
        // Retrieve the catalog task record
        var catalogTaskGR = new GlideRecord('sc_task');
        if (!catalogTaskGR.get(catalogTaskSysId)) {
            gs.error('Catalog task record not found: ' + catalogTaskSysId);
            return false;
        }

        var ritmSysId = catalogTaskGR.getValue('request_item');  // Get the RITM sys_id
        var ritmGR = new GlideRecord('sc_req_item');
        if (!ritmGR.get(ritmSysId)) {
            gs.error('RITM record not found for catalog task: ' + catalogTaskSysId);
            return false;
        }

        var catalogItemSysId = ritmGR.getValue('cat_item');  // Get the catalog item sys_id
        
        // Get checklist data for the catalog item from the system property
        var checklistData = this.getChecklistData(catalogItemSysId);
        if (!checklistData) {
            gs.error('No checklist data found for catalog item: ' + catalogItemSysId);
            return false;
        }

        var items = checklistData.items;
        if (!items || items.length === 0) {
            gs.error('No checklist items found for catalog item: ' + catalogItemSysId);
            return false;
        }

        // Check if all mandatory checklist items are completed
        for (var i = 0; i < items.length; i++) {
            var checklistItem = items[i];
            if (checklistItem.mandatory) { // Only check mandatory items
                var checklistItemGR = new GlideRecord('checklist_item');
                checklistItemGR.addQuery('checklist', checklistSysId);
                checklistItemGR.addQuery('name', checklistItem.name);  // Match the item name from property
                checklistItemGR.query();

                if (!checklistItemGR.next() || checklistItemGR.getValue('complete') !== '1') {  // Use 'complete' field to check completion
                    gs.info('Mandatory checklist item not completed: ' + checklistItem.name);
                    return false;
                }
            }
        }

        // All mandatory items are completed
        return true;
    } catch (e) {
        gs.error('Unexpected error occurred in areMandatoryChecklistItemsChecked: ' + e.message);
        return false;
    }
},


    type: 'ChecklistCreator'
};

 

Business Rule

The Global Scope Business Rule runs when a catalog task is created (inserted) or updated (on state change). The ChecklistCreator Script Include is called to manage checklist creation and validation.

  • On Insert: When you create a catalog task, the Business Rule retrieves the requested item (RITM) linked to the task. It uses the catalog item sys_id to get the corresponding checklist data from the system property. If the data is found and the short description of the task matches the checklist name, the checklist is created.
  • On Update (When Task Is Closing): When the catalog task is updated to a closed state, the Business Rule checks whether all mandatory checklist items are complete. The associated checklist record is queried, and the ChecklistCreator Script Include validates the completion status of mandatory items. If any mandatory item is incomplete, the task closure is blocked, and an error message is shown.

Global Scope Business Rule
Name: Create and Validate Checklists
When: Before INSERT and UPDATE
Table: Catalog Task
Condition:
Add appropriate condition so this BR executes for your Catalog items

/**
 * Business Rule to create and validate checklists for catalog tasks.
 * 
 * This Business Rule triggers on both insert and update operations:
 * - On insert: it creates a checklist for the catalog task if defined in the system property.
 * - On update: it validates if all mandatory checklist items are completed before closing the task.
 * 
 * @param {GlideRecord} current - The current record being processed (sc_task).
 * @param {GlideRecord} previous - The previous version of the record (null when async).
 */
(function executeRule(current, previous /*null when async*/) {
    try {
        // Instantiate the ChecklistCreator Script Include from the scoped application
        var checklistCreator = new x_916860_autocklst.ChecklistCreator();

        /**
         * Case 1: Checklist Creation on Insert
         * 
         * If a new catalog task is inserted, the script checks if a checklist needs to be created 
         * based on the catalog item and the short description of the task.
         */
        if (current.operation() == 'insert') {
            // Get the associated Requested Item (RITM) record
            var ritmGR = current.request_item.getRefRecord();
            if (ritmGR.isValidRecord()) {
                // Get the catalog item sys_id from the RITM record
                var catalogItemSysId = ritmGR.getValue('cat_item');
                // Retrieve checklist data from the system property
                var checklistData = checklistCreator.getChecklistData(catalogItemSysId);

                // If checklist data is found and the short description matches the checklist name, create the checklist
                if (checklistData && current.getValue("short_description") == checklistData.checklist_name) {
                    checklistCreator.createChecklistsForCatalogTask(current.sys_id, checklistData);
                }
            }
        }

        /**
         * Case 2: Checklist Validation on Update
         * 
         * If the catalog task is being updated to the Closed Complete state, the script checks 
         * if all mandatory checklist items are completed before allowing the task to close.
         */
        if (current.operation() == 'update' && current.state.changesTo('3')) {  // '3' represents Closed Complete state
            // Retrieve the associated checklist record for the current task
            var checklistGR = new GlideRecord('checklist');
            if (checklistGR.get('document', current.sys_id)) {
                // Validate if all mandatory checklist items are checked
                var allChecked = checklistCreator.areMandatoryChecklistItemsChecked(current.sys_id, checklistGR.sys_id);

                // If not all mandatory checklist items are checked, abort the closure and show an error message
                if (!allChecked) {
                    gs.addErrorMessage('There are mandatory checklist items that are not completed.');
                    current.setAbortAction(true);  // Prevent closure if mandatory items are not checked
                }
            }
        }

    } catch (e) {
        // Log any unexpected errors that occur during the execution of the Business Rule
        gs.error('Unexpected error in Business Rule Create and Validate Checklists: ' + e.message);
    }
})(current, previous);

 

 

Summary

By using ServiceNow’s Script Include and Business Rule, you can automate checklist creation and validation for catalog tasks, ensuring consistency and efficiency. You define checklists dynamically in a system property using a JSON format, which allows you to customize checklist items for each catalog task, including the order, mandatory status, and checklist names.

For smaller setups, the system property works well. However, for larger checklist configurations, you can create a custom table in your scoped application to store the checklist data. This makes managing a large number of checklists easier and more flexible.

With this automated process, you prevent task closures until all mandatory checklist items are completed. This reduces manual work, minimizes errors, and ensures consistent task management across your organization.

The post ServiceNow Checklist Automation: Simplifying Catalog Task Management appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/scripting/servicenow-checklist-automation-simplifying-catalog-task-management/feed/ 2
Demystifying SAML 2.0 Single Sign-On in ServiceNow https://servicenowguru.com/single-sign-on/demystifying-saml/ Wed, 24 Jul 2024 19:00:12 +0000 https://servicenowguru.com/?p=15649 This article helps you understand the SAML 2.0 SSO setup, focusing on how ServiceNow works with an Identity Provider (IDP) like Okta. It's essential for ServiceNow developers who need to troubleshoot SAML-related issues confidently. By breaking down the processes involved in SAML requests and responses, this guide empowers developers to resolve complex SSO problems. Whether

The post Demystifying SAML 2.0 Single Sign-On in ServiceNow appeared first on ServiceNow Guru.

]]>
This article helps you understand the SAML 2.0 SSO setup, focusing on how ServiceNow works with an Identity Provider (IDP) like Okta. It’s essential for ServiceNow developers who need to troubleshoot SAML-related issues confidently. By breaking down the processes involved in SAML requests and responses, this guide empowers developers to resolve complex SSO problems. Whether you are dealing with well-documented identity providers or those with limited documentation, understanding the underlying mechanisms of SAML 2.0 will help you achieve smoother and more secure integrations.

As data security becomes more important, this article also helps you understand other encryption and signing processes in ServiceNow. The ServiceNow Vault application uses similar concepts, highlighting the importance of grasping these security mechanisms.

Article Roadmap

  1. What is the Purpose of This Article
  2. Basic Flow Diagram Between ServiceNow and an IDP
  3. Theory on SAML and Its Flow
  4. Understanding and Establishing Trust Between SP and IDP
  5. Metadata Templates with Explanations
  6. Manual SSO Login and Debugging with Encryption and Signing
  7. Using Tools to Debug SAML Requests and Responses
  8. Understanding SAML Request and Response Structure
  9. How ServiceNow Processes the SAML Response
  10. SSO Request and Response Without Encryption
  11. SAML Logout
  12. Conclusion
  13. Next Steps: OpenID Connect

What is the Purpose of This Article

ServiceNow provides excellent documentation on setting up Single Sign-On (SSO), which you can find here. Usually, you just need to configure some properties in ServiceNow and the IDP (Identity Provider, e.g., Microsoft Azure Active Directory, Okta, OneLogin, Google Cloud Identity), making the setup relatively easy. Most of the time, following their documentation will get SSO working without any issues.

However, when setting up Single Sign-On with Identity Providers that have limited or confusing documentation (e.g., public or government-owned SSO) or when the SSO setup doesn’t work as expected, understanding the background processes can help you solve difficult problems.

This article aims to solve this problem by providing a basic understanding of the SAML 2.0 SSO setup. This will help ServiceNow developers troubleshoot SAML-related issues with more confidence. We will explore how SAML requests and responses work, breaking down the processes involved.

This guide follows up on my first article on Cryptography in ServiceNow.  To fully understand the concepts discussed here, I recommend reading the earlier article to grasp the basics of encoding, encryption and signing used in SAML.

While we will use Okta as our Identity Provider (IDP) example but the concepts will apply to any IDP.

Now, lets dive in and see how the Single Sign-On SAML Flow works.

Basic Flow Between ServiceNow and an IDP

In this section, we will be using the following terms:

  • SP (Service Provider) – This refers to any application that wants to leverage or consume the authentication services of an IDP. In this article, ServiceNow, as our SP, uses Okta to authenticate users.
  • IDP (Identity Provider) – In this article, Okta is the IDP. The IDP authenticates the user and sends the user’s details back to the SP.
  • SAML Assertion – Once the user is authenticated, the IDP sends back the authenticated user’s information to ServiceNow. The IDP includes this information as an XML tag in the SAML response sent to the SP. You might see a Service Provider (SP) called a Relying Party (RP), Application Service Provider (ASP), Consumer, or Resource Server. Similarly, people might refer to an Identity Provider (IDP) as an Authorization Server, Identity Assertion Provider, Authentication Server, or Issuer. So, when you encounter these terms, remember they all mean the same thing but in a different context.

Types of SAML Flows

There are two types of SAML flows to get the user authenticated and these flows are called SAML profiles.

Service Provider (SP)-Initiated SAML SSO Flow

In the SP-Initiated flow, the Service Provider (SP), like ServiceNow, starts the authentication process:

  • The user tries to access the ServiceNow instance.
  • ServiceNow redirects the user to the Identity Provider (IDP) for authentication.

Identity Provider (IDP)-Initiated SAML SSO Flow

In the IDP-Initiated flow, the Identity Provider (IDP) starts the authentication process:

  • The user logs in to the Identity Provider’s site first.
  • The user selects the Service Provider or application to access from the IDP’s dashboard that lists all available applications.
  • The Identity Provider sends a SAML assertion (an XML in the SAML response containing the user’s authenticated information) to the Service Provider to authenticate the user.

In this article we will focus on SP initiated SAML SSO Flow as shown in the diagram below:

SP initiates SAML SSO Flow

 

The diagram shows the SP-Initiated SAML SSO (Single Sign-On) process. It explains how a user, ServiceNow (as the Service Provider), and an Identity Provider (IDP, like Okta) interact. Here’s a simple breakdown of each step:

1. User Access Request

The user tries to access the ServiceNow application. This action starts the SSO process.

2. ServiceNow Forwards Request to IDP (Okta)

Next, ServiceNow sends the user to the Identity Provider (IDP) using an HTTP Redirect or HTTP Post. Although these methods are not critical to know in detail, we will use HTTP Redirect in this article.

Using HTTP Redirect

ServiceNow Redirects to IDP: ServiceNow redirects the user to the IDP (Okta) using the user’s browser (User Agent).

302 Status Response: In this step, ServiceNow, acting as the Service Provider (SP), sends a 302 status response to the browser. This response tells the browser to redirect the request to the IDP (Okta) for user authentication.

Using HTTP POST

Alternatively, ServiceNow can use HTTP POST.

HTML Form Creation: ServiceNow creates an HTML form containing the SAML request data.

Form Submission: This form is sent to the user’s browser, which automatically submits it to the IDP (Okta) via an HTTP POST request.

3. IDP (Okta) Displays Login Screen and Authenticates User

Once the request reaches the IDP, the IDP shows a login screen to the user. The user enters their credentials (username and password). The IDP (Okta) checks the user’s credentials. If the credentials are correct, the IDP creates a SAML response with the user’s information.

4. IDP (Okta) Forwards Response to ServiceNow

Finally, the IDP sends the SAML response back to ServiceNow through the user’s browser. ServiceNow reads the SAML response, checks it, and grants the user access based on their roles and permissions in ServiceNow.

Now that we’ve explored the SAML flow, let’s move on to understanding and establishing trust between the Service Provider (SP) and the Identity Provider (IDP).

Understanding and Establishing Trust between SP and IDP

Now you need to sign SAML requests and SAML responses, and it’s better to encrypt the SAML response as well. For signed and encrypted messages to work between the IDP (Okta) and SP (ServiceNow), both parties need to know each other. They establish this by sharing information and certificates, creating trust.

Trust in SAML and SSO means a secure relationship between the Service Provider (ServiceNow) and the Identity Provider (Okta). You establish this trust by exchanging metadata, certificates, and keys, which ensures both parties can securely authenticate and authorize users.

In short, you establish trust by exchanging detailed information about the IDP and SP using XML data called metadata. You can do this automatically (if the SP and IDP have a URL for it) or manually.

Let’s take a look at how metadata from ServiceNow and Okta look and understand what is included inside it. You can use these templates to manually create metadata for your ServiceNow instance.

Metadata Templates with Explanations

Here are the metadata templates for ServiceNow and Okta, along with explanations of the important attributes and their values.

SP (Service Provider) Metadata Template (ServiceNow)

<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="{SP Entity ID or Name}">
    <SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <KeyDescriptor use="signing">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>{Signing Certificate}</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </KeyDescriptor>
        <KeyDescriptor use="encryption">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>{Encryption Certificate}</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </KeyDescriptor>
        <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="{SP Single Logout Service URL}"/>
        <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
        <AssertionConsumerService isDefault="true" index="0" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="{SP Assertion Consumer Service URL 1}"/>
        <AssertionConsumerService isDefault="false" index="1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="{SP Assertion Consumer Service URL 2}"/>
    </SPSSODescriptor>
</EntityDescriptor>

EntityDescriptor entityID: You set this as the unique identifier for your ServiceNow instance, like “https://yourinstance.service-now.com”. While the definition allows for any unique identifier to name and identify the service provider, in ServiceNow, it always needs to be the instance URL.

SPSSODescriptor AuthnRequestsSigned: When you set this to “true,” ServiceNow will sign authentication requests.

WantAssertionsSigned: When you set this to “true,” ServiceNow expects the SAML assertions it receives to be signed.

KeyDescriptor use=”signing”: This section includes the certificate you use to sign SAML messages in ServiceNow. Replace {Signing Certificate} with your actual certificate. You can find the signing certificate in the X.509 Certificates (sys_certificate) table in the form of keystores. The sys_id for the signing keystore record is specified in the sys_property glide.authenticate.sso.saml2.keystore
If you want to add your own keystore, you also need to change this property.

KeyDescriptor use=”encryption”: This section includes the certificate you use to decrypt SAML messages in ServiceNow. Replace {Encryption Certificate} with your actual certificate.
You can find the encryption certificate in the X.509 Certificates (sys_certificate) table in the form of keystores. The sys_id for the encryption keystore record is specified in the sys_property glide.authenticate.sso.saml2.encryption.keystore

You can use pkitools to fetch the keys from the keystore. However, you should do this only for testing and non-production keys.

AssertionConsumerService Location: You set this as the URL where the IDP will send the SAML response, like “https://yourinstance.service-now.com/navpage.do”. There can be multiple tags for AssertionConsumerService, each with an index. ServiceNow normally has two: “https://yourinstance.service-now.com/navpage.do” and “https://yourinstance.service-now.com/consumer.do”.

Identity Provider (IDP) Metadata Template (Okta)

<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor entityID="{IDP Entity ID}"
    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
    <md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <md:KeyDescriptor use="signing">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>{Signing Certificate}</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:KeyDescriptor use="encryption">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>{Encryption Certificate}</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="{SingleLogoutService POST URL}"/>
        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="{SingleLogoutService Redirect URL}"/>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
        <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="{SingleSignOnService POST URL}"/>
        <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="{SingleSignOnService Redirect URL}"/>
    </md:IDPSSODescriptor>
</md:EntityDescriptor>

EntityDescriptor entityID: You set this as the unique identifier for your Identity Provider (IDP). For Okta, this is typically your Okta instance URL or a unique identifier specific to your Okta configuration.

IDPSSODescriptor WantAuthnRequestsSigned: This specifies whether the IDP wants to sign authentication requests.

KeyDescriptor use=”signing”: Okta signs the SAML assertions with this certificate.

KeyDescriptor use=”encryption”: Okta encrypts the SAML assertions with this certificate.

SingleLogoutService Location: The IDP handles logout requests at this URL. ServiceNow needs to send the logout requests to this URL. For most IDPs, this URL is usually the same for both HTTP-POST and HTTP-Redirect requests.

NameIDFormat: This specifies how to format the name identifier. In this example, it uses the email address format “urn:oasis:names:tc:SAML:1.1:nameid-format”. This means the user’s email address will be used as their unique identifier.

SingleSignOnService Location: The IDP handles signon requests at this URL. ServiceNow needs to send the signon requests to this URL. For most IDPs, this URL is usually the same for both HTTP-POST and HTTP-Redirect requests.

Now that we understand the SAML flow and the trust established between the Service Provider (SP) and Identity Provider (IDP), let’s move on to a practical approach. In this section, we will manually create an SSO login URL, send it to the IDP, receive the response, and use various tools to debug and dissect the request and response.

Manual SSO Login and Debugging

This is the section where the actual fun starts. We’ll manually create an SSO login URL using the metadata from the configured ServiceNow Identity Provider record. We will look at specific details from both ServiceNow and Okta settings.

I’ll provide screenshots: one from ServiceNow showing the Identity Provider record and another from Okta displaying the settings. We will also review the metadata for both the Service Provider (SP) and the Identity Provider (IDP).

We will enable all security options, including signing and encryption, so that we can cover everything in a single topic. This will help you understand the SSO process and troubleshoot any issues.

Note: This article will not cover the setup of SSO between ServiceNow and Okta. You can follow the detailed guide here for that purpose.

Now, let’s move on to creating a SAML SSO login URL using the gathered information.

Creating a SAML SSO Login URL

Let’s walk through the steps to manually create a SAML SSO login URL using the metadata and settings from ServiceNow and Okta.

Step 1: Review the ServiceNow Identity Provider Settings

First, look at the ServiceNow Identity Provider settings. Below is a screenshot of the Identity Provider record in ServiceNow. ServiceNow Identity Provider RecordWe need key information from this settings page, including the Entity ID (Field name in image is Identity Provider URL) , Single Sign-On Service URL (Field name in image is Identity Provider’s AuthnRequest), and the certificates for signing and encryption.
As explained belore, the signing and encryption certificates are added to the X.509 Certificates (sys_certificate) table and the sys_id’s of these records are updated in the properties glide.authenticate.sso.saml2.keystore and glide.authenticate.sso.saml2.encryption.keystore respectively.

Step 2: Review the Okta Application SAML Settings

Next, refer to the Okta Application SAML settings. Below is a screenshot of the SAML settings in Okta.

The values seen in this screeshot mostly reflect the setting from servicenow.

Okta Application SAML Settings

Okta Application SAML Settings

Step 3: Gather Metadata from ServiceNow

Here is the metadata XML from ServiceNow:

<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://dev216916.service-now.com">
 	<SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <KeyDescriptor use="signing" >
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIFXDCCA0SgAwIBAgIKIhQRkXF2J4F0QzANBgkqhkiG9w0BAQsFADBCMRcwFQYDVQQDDA5TZXJ2
Y2llbm93R3VydTENMAsGA1UECgwEU0FNTDELMAkGA1UECAwCREsxCzAJBgNVBAcMAkRLMB4XDTI0
MDYwNTIyNTAxN1oXDTI1MDYwNTIyNTAxN1owQjEXMBUGA1UEAwwOU2VydmNpZW5vd0d1cnUxDTAL
BgNVBAoMBFNBTUwxCzAJBgNVBAgMAkRLMQswCQYDVQQHDAJESzCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAJa01a4nGSiCLP1Lz3ApEAbsYfsLtNi8Ngh2r9r1FnV+ytyPSLJiXXkZvIqO
ICGFkr7HKVeB63FnCSu0Z7VBGB4Eoq9HDcgL9wdlLE4duD+O4gmAjxsJrBQDDTpPLv/ZQyRKM+ca
48Wb/RyantXONe3zbQMd4RlENBrvIYS82oK69oiXqJJl436JO6x9868P4Fy1Ih6wUXMaxqp2Kb+R
NXEegjeBPyA8DQCGKfGy1wRYG1BLzldHFo1Q0+jj1GADIX8NcwIxRrwvU4wpfSm0YH94s3lITjC1
Nnj0xt5hn+l7Yqn9kRzLe0LE18PojKqYq19Qw1pznVLZqZyb3ctNK5/wAiz/PTT+W0bFDOs4G6RZ
mlTDeiYkW2jD9q/3eNTmC/7KW640qBLqFNvHJjTf9Vba/zprUA2+LftH6LDVLMg0g+8RnV4xGbyd
lq0A3HlKIRz0gAjUZERRupMHeOzjE4iRy3ZPGY+1dS1r07IowVgo5BjFCyGG74zL81Du1VkpswYn
JjSy3Xjft9iyb3S7mxA+8YUeRUXEutZOv7PXDJE9J/3y+GVgljH3n4W+aFmRv1G3KQ3CcXM9pG/B
moF3a8K7JDGC1BDCiuc2bwVTXJJ07XHQkWByXHCheGX7OhHfQ+fkYBFlf4E3I7gUi94EiNfykeim
NLvOeJHJSATElylHAgMBAAGjVDBSMB0GA1UdDgQWBBQ2OfnLQ5vF64MfPkdNu+7ElPOIuzALBgNV
HQ8EBAMCAYYwDAYDVR0TBAUwAwEB/zAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDANBgkqhkiG9w0B
AQsFAAOCAgEAF1OcW5Sy9xIcrNPuv589d+mOIxl3wSPCZHAMzxnTWn1EanElQzciGvMWdX6m8zzI
TgNOdXJvJ4vU9mvKJQPnWhMLYrsN3mK1l8XS8/n2MRM6IXc3ve/U8y/Impy/8oow2cdmkkT42n3P
8c1uwkzoSCAYirljY9Cti/JdxVvLWuIbKEfctEEzvSGgX7ouJPoPftWObMSVtkwSHOm256Tpcd9H
m2YrxCXhxq5zgy1bMSoOc9aH3n/a1qoKRmvrD6xXzfGko1bMYmTYZwJeeVwELAxIrmE7/dD1A4Ba
EDC4OzIeLwvyIEgqHDqpX2Rng/etgfj0W5bVNAkua+VdEjUys7EGJot2+QL1wRgFDHHpRBjuJJR5
zc3d9IFJVfd6qoaWEEi6r3QWvldeaz+xzHahbXfRRWVYyr8xJHCkMfZujKxQPy6ui61M8F1MzrVV
dVM/HPGwG8QzGqXr8cOcGKqg5dJwVh6A96wW3thFl7ROwbJlPCJAi7UvAYQBAlakRGqZ3GQOJ1Ya
RRjfSue3mSWOWdN2pCHAjFCAswafCZdCIbjjdQxzrePyXSnsJ8GtgKM1AxTsSqa1mstgDxG42Dtl
TubyaAvfW5jItdD1mou5Kq2U8AV1VhJ+sbHug0NyP6PC6YeBx1stjM5N0rJ2cKGH51SuZbqOsTbj
qvZrqJaSuGg=</ds:X509Certificate></ds:X509Data></ds:KeyInfo>
        </KeyDescriptor>
        <KeyDescriptor use="encryption" >
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIFXDCCA0SgAwIBAgIKIhQRkXF2KAA3mTANBgkqhkiG9w0BAQsFADBCMRcwFQYDVQQDDA5TZXJ2
Y2llbm93R3VydTENMAsGA1UECgwEU0FNTDELMAkGA1UECAwCREsxCzAJBgNVBAcMAkRLMB4XDTI0
MDYwNTIyNTMyM1oXDTI1MDYwNTIyNTMyM1owQjEXMBUGA1UEAwwOU2VydmNpZW5vd0d1cnUxDTAL
BgNVBAoMBFNBTUwxCzAJBgNVBAgMAkRLMQswCQYDVQQHDAJESzCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAMYBnr1xo3V/fGAamjBH1l1iXvCrDnUaHXcjCCq7MkDJXb8U19BxWfO6XEDo
j2N/hTF70uWb6LhOZe+zqkqqwUyXXCxuZSo8XnpXDoTUAf3BvW0xhBZtaRbkm8aoJsJTSDBuYr92
FZczWhNR4/J2jnYD4J4uNvpmh3iBO80ca5jAkAIWMnN+Fpr4or+u1oAZDbiJqNHjxCKfAq9nMcKN
8ECRA70+BdpLmX5KIefR80BrdozHlOHfBvlyaTWP1+YkYvdo/mY3ahUnZgKS6I7kbVYn0BhxgyBi
G2gx4Yl9+R4jiP69etJqym7r1cSd65YQURMZlvpq1MUisjjfjIdHk+3W3qaY4y2rJUGwPf4xzyex
kOefR7l2YO6yZxiw5DJ0ArmPSAH3OSAUHHrwB+c9SoId7DSpKOOf+mt9/kcFi76ALlBc58D4D7La
0DZ7NssMgcgutl/Q5ETxM6w3AGC/C05zmFHKxEOUsHzu0M0DzElWhvAc4wg1uaZjVgfGC/pl5zAE
9Nkm0EAQLb2CGC3FMjxOE+My4weyiVF+sUqwIvgdyzUg4l8fwr6tTp5fuYZljTj08boT7QqAxruS
BBZ7BCGzZY8Px+W4MZXj/powp9y7As8oFpPZY4vcMmhigRTi/ocXrQeBm7KaHwMnsXXYotg9KE3u
UGbz9/LFGiKsFuLbAgMBAAGjVDBSMB0GA1UdDgQWBBTYdap3IO58YdL5khQHJ9qyGL3xxDALBgNV
HQ8EBAMCAYYwDAYDVR0TBAUwAwEB/zAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDANBgkqhkiG9w0B
AQsFAAOCAgEAr/ERTjCi09xd+jZgGlSPLeadq3WK9hLlIrRQHdcUJ79YSAQSkO97x580Owi+5Qji
k3RkQHLH4XdcKElz67ILzf5kbBhYA3bXy3kzaFqMSujzVg3Cg5oUSGXp8o6wQAIixcQbjOUPq3Uv
6PEMe94rLR7d3pJgSFTSpUTdu7Nu3hTZ5BVvgcEx/++mgsCZIEUe9h0zfOrNUUk/kzeNgc9jvL+n
18LttqHYormLU2pT7dUKBFbF/nZkxevBwPn7rD3KJFwq/gJaXPjhJpPtj2kRNqC4CLd7cXm2suv4
kn5qQlreOOXa3OO2fAPMHCeoSBX5dPWBK9RT1N9psNUhRuz8NfxKU3+5x1udPBxgM/gNlT/piyrq
jbxVqI1sP2eh3vG3ZXHXoeNbJWKnzcRa8ISYa4NHskeU9kPZ5QIhTNcaBlJka0CQ06uEaNa44e+N
xQFCWGssqaMJ2BKRl6gMhBUwLE4Ldw9Z5TgBXq5M58uC6lck/m5PlOl8HKykt8RqYed09MR8A5Uw
Ji+noV27el6EBMt0SlZsw+78mk+ieLI+UbnzxjqfLK/v/fc+mEV0FWbZjKehb5kwT947vyd/1GdK
divPOt3z4UrWNYtquzuaWW6FMyKFDk4CVvIe9pOV6t6mM9wMp6/GapNhvdXuWxrWQXjp7Wti0yBA
UUNvYcQM5e0=</ds:X509Certificate></ds:X509Data></ds:KeyInfo>
        </KeyDescriptor>
        <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev216916.service-now.com/navpage.do"/>
        <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
        <AssertionConsumerService isDefault="true" index="0" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev216916.service-now.com/navpage.do" />
        <AssertionConsumerService isDefault="false" index="1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev216916.service-now.com/consumer.do" />
    </SPSSODescriptor>
</EntityDescriptor>

Step 4: Gather Metadata from Okta

Here is the metadata XML from Okta:

<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor entityID="http://www.okta.com/exkhbgik0lUIiSbJO5d7"
    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
    <md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <md:KeyDescriptor use="signing">
            <ds:KeyInfo
                xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>MIIDqDCCApCgAwIBAgIGAY+v5nqHMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0wNjAzNzM4NzEcMBoGCSqGSIb3DQEJ
ARYNaW5mb0Bva3RhLmNvbTAeFw0yNDA1MjUxMzE2NDhaFw0zNDA1MjUxMzE3NDhaMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsG
A1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0wNjAzNzM4NzEc
MBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAJF10PKyrOkMEZx2re11K7djM9xTG9liOfBMbjee/bxtev+AOXsSg7tXJs6Td3UbX+U5F6lJ
LgoF1ukI9JMgBBrFXbV03PloIuVfsFcCem1Gd6vnEzQ6tN4RERi7JQQt71s/Geo6AhT7HtDvClsZ
EWX+aFH3stoSZPukzuqUXHL21PpqYZRkNn9w+ar0PqH6BVvtTaOzRfYXqljlFDiBhLmr+ljN2393
Fcpa11jJE1xOSddHpXr4hSXW5UvL2gebcyoyEwPBWFhoIoemH3Ai14gpG9Pd8A8X7Qx+YrEruq8n
uQCDoD1BCPbKFyzIriy9cfX1SGVJ1WS9ObpTHIKNErkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
QlT3S/oWWXan6f9COy9RQYN7QE5+WHtQAMf5ABankqb2vd9wrAro/79+ToxfahGpXEEWl7p9jSw0
6GugcUGbSNSd+SdjT+vyZ0qe2FkcjpCPeO7CjKvnPINIWyc8WaVX7Qb1XD5lPOzyhnivAsAj90Ll
7DbhTUpyiAkHAdE9epVXk2XowWVMfJN22t9xNhMPsV/19wQCga7ir3j7Ljvg/N2Vv/B+JNchbYeo
oqB5Wd1TUmAQqKR2CggMQlwlUXqrdTv0WEGjM4TaknV3iTkW/fVxp/lpYcRBaX+iDr+JfpXpOI4E
Xlrn/ZLnWyZnZz7YnSnWjpl8oKAMY2k1HQAx8Q==</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/slo/saml"/>
        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/slo/saml"/>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
        <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml"/>
        <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml"/>
    </md:IDPSSODescriptor>
</md:EntityDescriptor>

The important information that we need from here are the SingleSignOnService, SingleLogoutService, the Signing certificate and entityID

Important Note

As you can see, the public keys are listed in the metadata. When metadata is used, the Identity Provider (IDP) and the Service Provider (SP) exchange these keys, which are then used to decrypt the signed and encrypted requests. Ensuring you have these public keys correctly configured is crucial for the SAML setup to function securely and correctly.

Step 5: Prepare the SAML Request XML

This is the section where we prepare the SAML Request XML. We’ll use a template and replace placeholders with the correct values from the metadata we’ve gathered. The template for the SAML Request XML is as follows:

<saml2p:AuthnRequest
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
    AssertionConsumerServiceURL="{SP-ACS-URL}"
    Destination="{IDP-SSO-URL}"
    ID="{UNIQUE-GENERATED-ID}"
    IssueInstant="2021-10-14T18:41:20.295Z"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Version="2.0">
    <saml2:Issuer
        xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">{SP-ENTITY-ID}
    </saml2:Issuer>
</saml2p:AuthnRequest>

Replacing the Placeholders

  1. AssertionConsumerServiceURL: This URL is where the IDP will send the SAML response. I will get this from my ServiceNow metadata from Step 3. The value is https://dev216916.service-now.com/navpage.do.
  2. Destination: This is the Single Sign-On URL provided by the IDP, and I can get it from the Okta Metadata from Step 4. The value is https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml.
  3. ID: This is a unique identifier for the SAML request. You need to generate this using a ServiceNow script:
    SNC.SSOUtils.generateRequestId()

    I usually let ServiceNow generate the ID using the ‘Testing Connection’ UI action button from an IDP record and then copy the ID from the SAML logs. Since the ID needs to be added to the session, running a script or using other tools to generate the URL won’t save the ID in the session. This method allows ServiceNow to track the ID, which it references to check the validity of the SAML response.

  4. IssueInstant: The timestamp indicates when the SAML request is issued. Ensure it is in the correct format (ISO 8601). I will use my current time, i.e., 2024-06-08T18:41:20.295Z.
  5. Issuer: This is the entity ID of the Service Provider (SP), which is your ServiceNow instance URL or the entity ID you configured. I will use the entity ID from the ServiceNow metadata in Step 3. The value is https://dev216916.service-now.com.

Example with Replaced Values

Here’s how the XML might look after replacing the placeholders with actual values:

<saml2p:AuthnRequest
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
    AssertionConsumerServiceURL="https://dev216916.service-now.com/navpage.do"
    Destination="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml"
    ID="SNC90de684c667bfa95b48e5679daf4895b"
    IssueInstant="2024-06-08T18:41:20.295Z"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Version="2.0">
    <saml2:Issuer
        xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://dev216916.service-now.com
    </saml2:Issuer>
</saml2p:AuthnRequest>

Step 6: Create, Encode, and Sign the SAML Request XML

In this step, we will generate a similar XML to the one in the previous step using a script and then encode and sign the SAML Request XML. If you want to get a quick reference on concepts of signing and encoding, you can check out my article on cryptography.

I have created a script that handles the compression, encoding, and signing of the SAML request, generating the final SSO URL. This script ensures your SAML requests are correctly formatted and secured. Additionally, you can use samltool.com to create such URLs. This website is very handy when dealing with SAML.

Here’s the complete script:

var saml2 = new SAML2_update1();  // Initialize with the default constructor

/** @type {string} IDP SSO URL */
var IDP_SSO_URL = "https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml";
/** @type {string} Assertion Consumer Service URL */
var ASSERTION_CONSUMER_SERVICE_URL = "https://dev216916.service-now.com/navpage.do";
/** @type {string} Protocol Binding */
var PROTOCOL_BINDING = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
/** @type {string} Request ID */
var REQUEST_ID = saml2.generateRequestID();
/** @type {object} Issue Instant */
var ISSUE_INSTANT = new Packages.org.joda.time.DateTime();
/** @type {string} Issuer Value */
var ISSUER_VALUE = "https://dev216916.service-now.com";
/** @type {string} Signature Algorithm */
var SIG_ALG = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
/** @type {string} Relay State */
var RELAY_STATE = "https://dev216916.service-now.com/navpage.do";
/** @type {string} Certificate ID */
var CERTIFICATE_ID = "2d6e2ba297220210768df52ad053af34";
/** @type {string} Alias */
var ALIAS = "saml2sp";
/** @type {string} Alias Password */
var ALIAS_PASSWORD = "saml2sp";

/** @type {object} Mapping for SigAlg to Signing Algorithm */
var sigAlgMapping = {
    "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256": "SHA256withRSA",
    "http://www.w3.org/2001/04/xmldsig-more#rsa-sha1": "SHA1withRSA",
    "http://www.w3.org/2000/09/xmldsig#rsa-md5": "MD5withRSA",
    "http://www.w3.org/2001/04/xmldsig-more#rsa-md2": "MD2withRSA",
    "http://www.w3.org/2001/04/xmldsig-more#rsa-sha224": "SHA224withRSA",
    "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384": "SHA384withRSA",
    "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512": "SHA512withRSA",
    "http://www.w3.org/2000/09/xmldsig#dsa-sha1": "SHA1withDSA",
    "http://www.w3.org/2001/04/xmldsig-more#dsa-sha256": "SHA256withDSA",
    "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1": "SHA1withECDSA",
    "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224": "SHA224withECDSA",
    "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256": "SHA256withECDSA",
    "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384": "SHA384withECDSA",
    "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512": "SHA512withECDSA"
};

try {
    /**
     * Manually create the AuthnRequest object with hardcoded values
     */
    var AuthnRequestBuilder = Packages.org.opensaml.saml2.core.impl.AuthnRequestBuilder;
    var AuthnRequestMarshaller = Packages.org.opensaml.saml2.core.impl.AuthnRequestMarshaller;
    var SAMLVersion = Packages.org.opensaml.common.SAMLVersion;

    var builder = new AuthnRequestBuilder();
    var authnRequest = builder.buildObject();
    authnRequest.setID(REQUEST_ID);
    authnRequest.setVersion(SAMLVersion.VERSION_20);
    authnRequest.setIssueInstant(ISSUE_INSTANT);
    authnRequest.setAssertionConsumerServiceURL(ASSERTION_CONSUMER_SERVICE_URL);
    authnRequest.setProtocolBinding(PROTOCOL_BINDING);

    var issuerBuilder = new Packages.org.opensaml.saml2.core.impl.IssuerBuilder();
    var issuer = issuerBuilder.buildObject();
    issuer.setValue(ISSUER_VALUE);

    authnRequest.setIssuer(issuer);
    authnRequest.setDestination(IDP_SSO_URL);

    /**
     * Marshall the AuthnRequest object to an XML element
     */
    var marshaller = new AuthnRequestMarshaller();
    var xmlElement = marshaller.marshall(authnRequest);

    /**
     * Convert the XML element to a string
     */
    var samlRequestString = GlideXMLUtil.toFragmentString(xmlElement.getOwnerDocument());
    gs.info("SAML Request: " + samlRequestString);

    /**
     * Deflate, Base64 encode, and URL encode the SAML request string
     */
    var deflatedEncodedRequest = saml2.getEncodedSAMLRequest(xmlElement, true, true);

    /**
     * Print the deflated and encoded SAML request (for debugging)
     */
    gs.info("Deflated and Encoded SAML Request: " + deflatedEncodedRequest);

    /**
     * Construct the final SSO URL
     */
    var ssoUrl = constructSSOUrl(IDP_SSO_URL, deflatedEncodedRequest);
    gs.info("SSO URL: " + ssoUrl);
} catch (e) {
    if (e instanceof Packages.java.lang.Throwable) {
        gs.logError(GlideLog.getStackTrace(e));
    } else {
        gs.logError(e.name + ": " + e.message);
    }
}

/**
 * Constructs the SSO URL with the given parameters.
 * @param {string} idpSSOUrl - The IDP SSO URL
 * @param {string} encodedSamlRequest - The encoded SAML request
 * @returns {string} - The constructed SSO URL
 */
function constructSSOUrl(idpSSOUrl, encodedSamlRequest) {
    /** Map SigAlg to Signing Algorithm */
    var signingAlgorithm = sigAlgMapping[SIG_ALG];

    /** Encode components */
    var encodedSigAlg = encodeURIComponent(SIG_ALG);
    var signature = generateSignature(encodedSamlRequest, signingAlgorithm);
    var encodedSignature = encodeURIComponent(signature);
    var encodedRelayState = encodeURIComponent(RELAY_STATE);

    /** Log each component of the URL */
    gs.info("Encoded SAML Request: " + encodedSamlRequest);
    gs.info("Signature Algorithm: " + SIG_ALG);
    gs.info("URI Encoded Signature Algorithm: " + encodedSigAlg);
    gs.info("Signature: " + signature);
    gs.info("URI Encoded Signature: " + encodedSignature);
    gs.info("Relay State: " + RELAY_STATE);
    gs.info("URI Encoded Relay State: " + encodedRelayState);

    /** Construct the SSO URL */
    var ssoUrl = idpSSOUrl + "?SAMLRequest=" + encodedSamlRequest +
                 "&SigAlg=" + encodedSigAlg +
                 "&Signature=" + encodedSignature +
                 "&RelayState=" + encodedRelayState;

    return ssoUrl;
}

/**
 * Generates a signature for the given SAML request.
 * @param {string} encodedSamlRequest - The encoded SAML request
 * @param {string} signingAlgorithm - The signing algorithm
 * @returns {string} - The generated signature
 */
function generateSignature(encodedSamlRequest, signingAlgorithm) {
    var gce = new GlideCertificateEncryption();
    return gce.sign(CERTIFICATE_ID, ALIAS, ALIAS_PASSWORD, signingAlgorithm, encodedSamlRequest);
}

 

Step 7: Manually Create the SSO Login URL

Using the information from the metadata, we will manually construct the SSO login URL. Here is the template for the URL:

<IDP-SSO-URL>?SAMLRequest=<SAML-REQUEST-URL-ENCODED>&SigAlg=<SIG-ALG>&Signature=<URL-ENCODED-SIGN>&RelayState=<URL-ENCODED-RELAY>

Replace the placeholders with the actual values extracted from the metadata and settings:

  • IDP-SLO-URL: The SingleSignOnService URL from the Okta metadata which we get from Step 4
    i.e., https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/slo/saml
  • SAML-REQUEST-URL-ENCODED: The Base64-encoded and URL-encoded SAML request. We need to deflate (compress) the SAML request as there are limitiation on how long an URL can be. This is also a reason why we should use HTTP Post instead of HTTP Redirect SAML Profiles.
  • SIG-ALG: The signing algorithm used (e.g., http://www.w3.org/2001/04/xmldsig-more#rsa-sha256).
  • URL-ENCODED-SIGN: The URL-encoded signature. Refer the article on cryptography
  • RelayState: Optional parameter to maintain state information.

We will use the script from the previous step to generate various components of the URL alomg with the final SSO Login URL

*** Script: SAML Request: <saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="https://dev216916.service-now.com/navpage.do" Destination="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml" ID="SNCc7a9ecb90a39a5757bba3efd2ab10da7" IssueInstant="2024-07-04T10:12:41.108Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://dev216916.service-now.com</saml2:Issuer></saml2p:AuthnRequest>
*** Script: SAML Request xml: <saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="https://dev216916.service-now.com/navpage.do" Destination="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml" ID="SNCc7a9ecb90a39a5757bba3efd2ab10da7" IssueInstant="2024-07-04T10:12:41.108Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://dev216916.service-now.com</saml2:Issuer></saml2p:AuthnRequest>
*** Script: Deflated and Encoded SAML Request: hVLBcoIwEP0VJncgATWSEWasHmrHVkewh16cAClmhIRmg%2B3nV9HO6MUed97bt7vv7QR4Uwctm3Z2rzbiqxNgnZ%2BmVsAuSIw6o5jmIIEp3ghgtmDp9HXJAg%2Bz1mirC10jZwogjJVazbSCrhEmFeYoC7HdLGO0t7YF5vulOAZkFJGRBxfUVfrbK3TjK35seSW8UiNnftpBKn4Wu2t18QiHNBxTTx8s79t4294hu6vuSbbqTFeKRu%2BIL34O%2B7ySB1xvFzLNX1bDkvoA2j%2BfiJzFPEbp26ygPBJFHmEeRnxIhzTPeSg%2By4DnBJecnogAnVgosFzZGAU4GLiYuniQEcxIwAbEI3j8gZz11ZUnqUqpqscW5hcSsOcsW7vrVZoh510Y6K8%2FEVAy6ZNg%2FXRzG85jYf6XCEr%2B9X%2Fi385IruX9WyS%2F
Found keyId : fdaef99e97a20210768df52ad053afbe in store : com.glide.kmf.KMFDBModuleKeyStore@22117d25
Found wrapped key in repo. Attempting to unwrap.
Successfully unwrapped key: fdaef99e97a20210768df52ad053afbe
*** Script: Encoded SAML Request: hVLBcoIwEP0VJncgATWSEWasHmrHVkewh16cAClmhIRmg%2B3nV9HO6MUed97bt7vv7QR4Uwctm3Z2rzbiqxNgnZ%2BmVsAuSIw6o5jmIIEp3ghgtmDp9HXJAg%2Bz1mirC10jZwogjJVazbSCrhEmFeYoC7HdLGO0t7YF5vulOAZkFJGRBxfUVfrbK3TjK35seSW8UiNnftpBKn4Wu2t18QiHNBxTTx8s79t4294hu6vuSbbqTFeKRu%2BIL34O%2B7ySB1xvFzLNX1bDkvoA2j%2BfiJzFPEbp26ygPBJFHmEeRnxIhzTPeSg%2By4DnBJecnogAnVgosFzZGAU4GLiYuniQEcxIwAbEI3j8gZz11ZUnqUqpqscW5hcSsOcsW7vrVZoh510Y6K8%2FEVAy6ZNg%2FXRzG85jYf6XCEr%2B9X%2Fi385IruX9WyS%2F
*** Script: Signature Algorithm: http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
*** Script: URI Encoded Signature Algorithm: http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256
*** Script: Signature: GokmsDs/qv7RvWy/uJbQ6GhZBnnnpKevpqgkjk/fdgW+Q1dND9+F9A0yUb1sRBHXlLgrkIqQiC5LAy0nuqcxllH1PJ/1UMVJd6lOg6skH8WCXSZbjTpbixN+IpgSszVUAypZ+j8DuhKxGs0CLfIHgDafPbAz5O7OwI1w1L/Z4BQfTTV+ayBwvWOHpc1QGJDcuqhV3AecX/f8MHh5RGQ9rgCyfOk5tmDSXOgl1pEh3/QDIDaNKVNPPmVj8qIEKOtn8OH0T3KMTqPOivYWnyn2TxcfdZB1z+MYQUvMQPqbxRrFyJxo7TX6FNAqam680UgmkKvdbc6bMTtaz8wlAqiXWIvWq8P5MgPiyTcGTSe33591NT6HCNcm9FxrpWD0NNQFC/n2aT0gM8yilp77IwNtE6in8X5IxHq8FHXO6XD/aZk8b/qd4ce/GKe4mZ6TCkCYlWiglWV2v1BlvaXwdM8kAbAimazC1oeAmRiDJ6GJR553pkEqDjGL5z9u78tBQoiaTzQMs92DK5Z+9uPO0oxkvB/NAFP7CFExXz2JKlO+8wNrdoecDX/4duZIAGCKihQwkcqwjE7VXzxM8x8rH1XbLI8telN/lMkMiza2T3SJSTGpp11ojfAKcDXdSdawbLnnyYhzEK6r2g9sI0zIdp+oTQ5VJm5oQAJ642SQseHYjDY=
*** Script: URI Encoded Signature: GokmsDs%2Fqv7RvWy%2FuJbQ6GhZBnnnpKevpqgkjk%2FfdgW%2BQ1dND9%2BF9A0yUb1sRBHXlLgrkIqQiC5LAy0nuqcxllH1PJ%2F1UMVJd6lOg6skH8WCXSZbjTpbixN%2BIpgSszVUAypZ%2Bj8DuhKxGs0CLfIHgDafPbAz5O7OwI1w1L%2FZ4BQfTTV%2BayBwvWOHpc1QGJDcuqhV3AecX%2Ff8MHh5RGQ9rgCyfOk5tmDSXOgl1pEh3%2FQDIDaNKVNPPmVj8qIEKOtn8OH0T3KMTqPOivYWnyn2TxcfdZB1z%2BMYQUvMQPqbxRrFyJxo7TX6FNAqam680UgmkKvdbc6bMTtaz8wlAqiXWIvWq8P5MgPiyTcGTSe33591NT6HCNcm9FxrpWD0NNQFC%2Fn2aT0gM8yilp77IwNtE6in8X5IxHq8FHXO6XD%2FaZk8b%2Fqd4ce%2FGKe4mZ6TCkCYlWiglWV2v1BlvaXwdM8kAbAimazC1oeAmRiDJ6GJR553pkEqDjGL5z9u78tBQoiaTzQMs92DK5Z%2B9uPO0oxkvB%2FNAFP7CFExXz2JKlO%2B8wNrdoecDX%2F4duZIAGCKihQwkcqwjE7VXzxM8x8rH1XbLI8telN%2FlMkMiza2T3SJSTGpp11ojfAKcDXdSdawbLnnyYhzEK6r2g9sI0zIdp%2BoTQ5VJm5oQAJ642SQseHYjDY%3D
*** Script: Relay State: https://dev216916.service-now.com/navpage.do
*** Script: URI Encoded Relay State: https%3A%2F%2Fdev216916.service-now.com%2Fnavpage.do
*** Script: SSO URL: https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml?SAMLRequest=hVLBcoIwEP0VJncgATWSEWasHmrHVkewh16cAClmhIRmg%2B3nV9HO6MUed97bt7vv7QR4Uwctm3Z2rzbiqxNgnZ%2BmVsAuSIw6o5jmIIEp3ghgtmDp9HXJAg%2Bz1mirC10jZwogjJVazbSCrhEmFeYoC7HdLGO0t7YF5vulOAZkFJGRBxfUVfrbK3TjK35seSW8UiNnftpBKn4Wu2t18QiHNBxTTx8s79t4294hu6vuSbbqTFeKRu%2BIL34O%2B7ySB1xvFzLNX1bDkvoA2j%2BfiJzFPEbp26ygPBJFHmEeRnxIhzTPeSg%2By4DnBJecnogAnVgosFzZGAU4GLiYuniQEcxIwAbEI3j8gZz11ZUnqUqpqscW5hcSsOcsW7vrVZoh510Y6K8%2FEVAy6ZNg%2FXRzG85jYf6XCEr%2B9X%2Fi385IruX9WyS%2F&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=GokmsDs%2Fqv7RvWy%2FuJbQ6GhZBnnnpKevpqgkjk%2FfdgW%2BQ1dND9%2BF9A0yUb1sRBHXlLgrkIqQiC5LAy0nuqcxllH1PJ%2F1UMVJd6lOg6skH8WCXSZbjTpbixN%2BIpgSszVUAypZ%2Bj8DuhKxGs0CLfIHgDafPbAz5O7OwI1w1L%2FZ4BQfTTV%2BayBwvWOHpc1QGJDcuqhV3AecX%2Ff8MHh5RGQ9rgCyfOk5tmDSXOgl1pEh3%2FQDIDaNKVNPPmVj8qIEKOtn8OH0T3KMTqPOivYWnyn2TxcfdZB1z%2BMYQUvMQPqbxRrFyJxo7TX6FNAqam680UgmkKvdbc6bMTtaz8wlAqiXWIvWq8P5MgPiyTcGTSe33591NT6HCNcm9FxrpWD0NNQFC%2Fn2aT0gM8yilp77IwNtE6in8X5IxHq8FHXO6XD%2FaZk8b%2Fqd4ce%2FGKe4mZ6TCkCYlWiglWV2v1BlvaXwdM8kAbAimazC1oeAmRiDJ6GJR553pkEqDjGL5z9u78tBQoiaTzQMs92DK5Z%2B9uPO0oxkvB%2FNAFP7CFExXz2JKlO%2B8wNrdoecDX%2F4duZIAGCKihQwkcqwjE7VXzxM8x8rH1XbLI8telN%2FlMkMiza2T3SJSTGpp11ojfAKcDXdSdawbLnnyYhzEK6r2g9sI0zIdp%2BoTQ5VJm5oQAJ642SQseHYjDY%3D&RelayState=https%3A%2F%2Fdev216916.service-now.com%2Fnavpage.do

The final SSO Login URL will look like this:

https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml?SAMLRequest=hVLBcoIwEP0VJncgATWSEWasHmrHVkewh16cAClmhIRmg%2B3nV9HO6MUed97bt7vv7QR4Uwctm3Z2rzbiqxNgnZ%2BmVsAuSIw6o5jmIIEp3ghgtmDp9HXJAg%2Bz1mirC10jZwogjJVazbSCrhEmFeYoC7HdLGO0t7YF5vulOAZkFJGRBxfUVfrbK3TjK35seSW8UiNnftpBKn4Wu2t18QiHNBxTTx8s79t4294hu6vuSbbqTFeKRu%2BIL34O%2B7ySB1xvFzLNX1bDkvoA2j%2BfiJzFPEbp26ygPBJFHmEeRnxIhzTPeSg%2By4DnBJecnogAnVgosFzZGAU4GLiYuniQEcxIwAbEI3j8gZz11ZUnqUqpqscW5hcSsOcsW7vrVZoh510Y6K8%2FEVAy6ZNg%2FXRzG85jYf6XCEr%2B9X%2Fi385IruX9WyS%2F&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=GokmsDs%2Fqv7RvWy%2FuJbQ6GhZBnnnpKevpqgkjk%2FfdgW%2BQ1dND9%2BF9A0yUb1sRBHXlLgrkIqQiC5LAy0nuqcxllH1PJ%2F1UMVJd6lOg6skH8WCXSZbjTpbixN%2BIpgSszVUAypZ%2Bj8DuhKxGs0CLfIHgDafPbAz5O7OwI1w1L%2FZ4BQfTTV%2BayBwvWOHpc1QGJDcuqhV3AecX%2Ff8MHh5RGQ9rgCyfOk5tmDSXOgl1pEh3%2FQDIDaNKVNPPmVj8qIEKOtn8OH0T3KMTqPOivYWnyn2TxcfdZB1z%2BMYQUvMQPqbxRrFyJxo7TX6FNAqam680UgmkKvdbc6bMTtaz8wlAqiXWIvWq8P5MgPiyTcGTSe33591NT6HCNcm9FxrpWD0NNQFC%2Fn2aT0gM8yilp77IwNtE6in8X5IxHq8FHXO6XD%2FaZk8b%2Fqd4ce%2FGKe4mZ6TCkCYlWiglWV2v1BlvaXwdM8kAbAimazC1oeAmRiDJ6GJR553pkEqDjGL5z9u78tBQoiaTzQMs92DK5Z%2B9uPO0oxkvB%2FNAFP7CFExXz2JKlO%2B8wNrdoecDX%2F4duZIAGCKihQwkcqwjE7VXzxM8x8rH1XbLI8telN%2FlMkMiza2T3SJSTGpp11ojfAKcDXdSdawbLnnyYhzEK6r2g9sI0zIdp%2BoTQ5VJm5oQAJ642SQseHYjDY%3D&RelayState=https%3A%2F%2Fdev216916.service-now.com%2Fnavpage.do

Step 8: Sending the SSO Login URL to the IDP

To check if our URL works, we open a new browser session and run the SSO URL, It will open the SSO login page from the IDP and allow us to enter the login credentians.
In my example, I am using an imaginary user that I have created in Okta.

Okta SSO login Screen

Step 9: Receiving and Analyzing the SAML Response

Incase there are errors, we need to be able to check the response from Okta. There are multiple ways to do this.

  1. Using the system logs
  2. Using some SAML Browser Extension

ServiceNow logs everything that happens during an SSO login process if you enable the sys_property called “glide.authenticate.multisso.debug.” However, since the system logs are shown in seconds, we do not see the exact order of events.

To dig deeper, we can find these precise logs, ordered chronologically to the millisecond, using the syslogs entries page. By using the exact second the SAML operation was performed and searching for “SAML2” as keywords, we can locate the proper logs.

In case of errors, it’s crucial to check the response from Okta. Here are a few methods to do this:

  1. Using the System Logs:
    ServiceNow logs all activities during an SSO login process if you enable the glide.authenticate.multisso.debug property. However, since the system logs are shown in seconds, they might not display events in the exact order as they occur.
    SAMLsysLog
    To dig deeper into the logs, use the syslogs entries page. Search for logs with the keyword “SAML2” and the exact second the SAML operation was performed. This method finds precise logs ordered chronologically to the millisecond, helping you identify the exact sequence of events and troubleshoot issues more effectively.
    syslog entries page
  2. Using SAML Browser Extensions:
    These extensions can help capture and analyze SAML responses directly from the browser. I personally use a Chrome extension called SAML DevTools Extension. Once enabled, you can view the details of SAML requests and responses in the browser’s developer tools. Now lets use this extension to anaylse the SAML request and Response in the next section.

Using Tools to Debug SAML Requests and Responses

When debugging SAML issues, the SAML DevTools extension is an invaluable tool. This Chrome extension allows you to view the details of SAML requests and responses directly within the browser’s developer tools. Once enabled, you can inspect the SAML transactions, including both the requests sent to the Identity Provider (IdP) and the responses received.

We will use this tool alongside ServiceNow logs to analyze the SAML response. This combined approach ensures a thorough examination of the SAML transactions for effective troubleshooting. Here are screenshots of the SAML Request XML and the SAML Response XML, which we will discuss in the next section:

SAML Request

SAML Response
SAML Response

Understanding SAML Request and Response Structure

In this section, we delve into the details of the SAML Response XML and explain how ServiceNow checks various attributes upon receiving the response. We have already covered the details of the SAML Request, so we will not discuss it again.

SAML Request XML

The SAML DevTools extension captured this example of a SAML Request XML:

<saml2p:AuthnRequest 
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" 
    AssertionConsumerServiceURL="https://dev216916.service-now.com/navpage.do" 
    Destination="https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml" 
    ForceAuthn="true" 
    ID="SNCed425771ce2bb7bf6285a36b78e1d2d4" 
    IsPassive="false" 
    IssueInstant="2024-07-04T12:00:43.409Z" 
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" 
    ProviderName="https://dev216916.service-now.com/navpage.do" 
    Version="2.0">
    <saml2:Issuer 
        xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://dev216916.service-now.com
    </saml2:Issuer>
    <saml2p:NameIDPolicy 
        AllowCreate="true" 
        Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
    <saml2p:RequestedAuthnContext 
        Comparison="exact">
        <saml2:AuthnContextClassRef 
            xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
        </saml2:AuthnContextClassRef>
    </saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>

XML Signatures

Before we look at the SAML response, it is important to understand XML Signatures for handling SAML responses like the one in our example. XML Signatures can sign the entire XML document or specific elements within it. In our ServiceNow example, we use an enveloped signature within the SAML response. Here’s a breakdown of the different types of XML signatures:

Enveloped Signature

An enveloped signature is when the signature is a descendant of the resource it signs. This means the signature is embedded within the XML data that it is intended to secure. By placing the signature within the signed data, it ensures that any alteration of the data will invalidate the signature, thus providing integrity and authenticity of the document.

In our example, the signature is within the <saml2p:Response> element. Here is how it looks:

<saml2p:Response ... ID="id8999474826387331185788317" ...>
    ...
    <ds:Signature>
        <ds:SignedInfo>
            ...
            <ds:Reference URI="#id8999474826387331185788317">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <ds:DigestValue>...</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>...</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>...</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    ...
</saml2p:Response>

Key Elements of the Enveloped Signature:

  • Signature: This element contains the digital signature.
  • SignedInfo: This element includes information on how the signature is generated, including the canonicalization and signature methods.
  • Reference: This element specifies the data being signed. The URI attribute refers to the ID of the <saml2p:Response> element.
  • Transforms: This element contains a list of transformations applied to the data before it is signed. The enveloped-signature transform ensures the signature is calculated excluding the <Signature> element itself.
  • DigestMethod: This element specifies the algorithm used to create the digest of the referenced data.
  • DigestValue: This element contains the actual digest value.
  • SignatureValue: This element contains the actual signature value, which is the result of signing the <SignedInfo> element.
  • KeyInfo: This element provides information about the key used to sign the document.
  • X509Data: This element includes the X.509 certificate containing the public key corresponding to the private key used to sign the document.
  • X509Certificate: This element contains the public key certificate.

Enveloping Signature

In enveloping signatures, the signature wraps the resource:

<ds:Signature>
    <ds:SignedInfo>
        ...
        <ds:Reference URI="#id8999474826387331185788317">
            ...
        </ds:Reference>
    </ds:SignedInfo>
    <samlp:Response ... ID="id8999474826387331185788317" ... >
        ...
    </samlp:Response>
</ds:Signature>

Detached Signature

Detached signatures are separate from the signed resource:

<samlp:Response ... ID="id8999474826387331185788317" ... >
    ...
</samlp:Response>
<ds:Signature>
    <ds:SignedInfo>
        ...
        <ds:Reference URI="#id8999474826387331185788317">
            ...
        </ds:Reference>
    </ds:SignedInfo>
</ds:Signature>

In our ServiceNow example, we see an enveloped signature, where the signature is within the SAML response it signs. This ensures the integrity and authenticity of the response.

With XML Signatures covered, let’s look at the SAML Response structure. In this section, we will explain how ServiceNow checks various attributes in the SAML Response for secure authentication.

SAML Response Structure

The IdP sends a SAML Response XML document to the Service Provider (SP) after authenticating the user. Here’s an example of a SAML Response:

<?xml 
version="1.0" 
encoding="UTF-8"?><saml2p:Response 
    Destination="https://dev216916.service-now.com/navpage.do" 
    ID="id8999474826387331185788317" 
    InResponseTo="SNCed425771ce2bb7bf6285a36b78e1d2d4" 
    IssueInstant="2024-07-04T12:01:31.372Z" 
    Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"><saml2:Issuer 
        Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exkhbgik0lUIiSbJO5d7
    </saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod 
                Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod 
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference 
                URI="#id8999474826387331185788317"><ds:Transforms><ds:Transform 
                        Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform 
                        Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod 
                    Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>XeNAhd/SkaA744B20SIL08bI+
                    z2kX1DA2Ej7IfYRLnk=
                </ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>YGBhT+yMu0C7XB2njOFhB/3fuphPaC3GeE3hgIQBxB0ZT3vrSk7lLWH1zP5h+phuvtKbhTClhMDv7H6LNi62qn4AeS0d2PJQjfIXj3giBxyRI1X85GOl11nGhrwpOfqtEp7Mm3maolNuBaHa6UktdhxkjZkZXn6rolmA2SPcSC9bhTODKopdVGcArkZioI/MO+zx6SUdONafLuVwV9EcctXIdbTVLYqgayhcSwweF1vUHxQwJATH42XY8SjdUnHECj5OUXuyG+1cNTSbrFP4XNKHGPcqOd/
            XVr4lNj0yCYUGn6kpXlWMhbJq1AIyLBQoI6pYFmhIjET9WqDVgqUebw==
        </ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDqDCCApCgAwIBAgIGAY+v5nqHMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0wNjAzNzM4NzEcMBoGCSqGSIb3DQEJ
ARYNaW5mb0Bva3RhLmNvbTAeFw0yNDA1MjUxMzE2NDhaFw0zNDA1MjUxMzE3NDhaMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsG
A1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0wNjAzNzM4NzEc
MBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAJF10PKyrOkMEZx2re11K7djM9xTG9liOfBMbjee/bxtev+AOXsSg7tXJs6Td3UbX+U5F6lJ
LgoF1ukI9JMgBBrFXbV03PloIuVfsFcCem1Gd6vnEzQ6tN4RERi7JQQt71s/Geo6AhT7HtDvClsZ
EWX+aFH3stoSZPukzuqUXHL21PpqYZRkNn9w+ar0PqH6BVvtTaOzRfYXqljlFDiBhLmr+ljN2393
Fcpa11jJE1xOSddHpXr4hSXW5UvL2gebcyoyEwPBWFhoIoemH3Ai14gpG9Pd8A8X7Qx+YrEruq8n
uQCDoD1BCPbKFyzIriy9cfX1SGVJ1WS9ObpTHIKNErkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
QlT3S/oWWXan6f9COy9RQYN7QE5+WHtQAMf5ABankqb2vd9wrAro/79+ToxfahGpXEEWl7p9jSw0
6GugcUGbSNSd+SdjT+vyZ0qe2FkcjpCPeO7CjKvnPINIWyc8WaVX7Qb1XD5lPOzyhnivAsAj90Ll
7DbhTUpyiAkHAdE9epVXk2XowWVMfJN22t9xNhMPsV/19wQCga7ir3j7Ljvg/N2Vv/B+JNchbYeo
oqB5Wd1TUmAQqKR2CggMQlwlUXqrdTv0WEGjM4TaknV3iTkW/fVxp/lpYcRBaX+iDr+JfpXpOI4E
Xlrn/
                    ZLnWyZnZz7YnSnWjpl8oKAMY2k1HQAx8Q==
                </ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"><saml2p:StatusCode 
            Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><xenc:EncryptedData 
            Id="_24bd7d84448b12589a8b12a697f44fa7" 
            Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod 
                Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:RetrievalMethod 
                    Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey" 
                    URI="#_62667646d33a28b6a656c1cb65b14d29"/></ds:KeyInfo><xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:CipherValue>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
                    FIZtVxukpfvIixgfxTCbajFUoHGJL0whtYKxyXqmGradwGgcVeBdzuxa6FaAM=
                </xenc:CipherValue></xenc:CipherData></xenc:EncryptedData><xenc:EncryptedKey 
            Id="_62667646d33a28b6a656c1cb65b14d29" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod 
                Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><ds:DigestMethod 
                    Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/></xenc:EncryptionMethod><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIFXDCCA0SgAwIBAgIKIhQRkXF2KAA3mTANBgkqhkiG9w0BAQsFADBCMRcwFQYDVQQDDA5TZXJ2
Y2llbm93R3VydTENMAsGA1UECgwEU0FNTDELMAkGA1UECAwCREsxCzAJBgNVBAcMAkRLMB4XDTI0
MDYwNTIyNTMyM1oXDTI1MDYwNTIyNTMyM1owQjEXMBUGA1UEAwwOU2VydmNpZW5vd0d1cnUxDTAL
BgNVBAoMBFNBTUwxCzAJBgNVBAgMAkRLMQswCQYDVQQHDAJESzCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAMYBnr1xo3V/fGAamjBH1l1iXvCrDnUaHXcjCCq7MkDJXb8U19BxWfO6XEDo
j2N/hTF70uWb6LhOZe+zqkqqwUyXXCxuZSo8XnpXDoTUAf3BvW0xhBZtaRbkm8aoJsJTSDBuYr92
FZczWhNR4/J2jnYD4J4uNvpmh3iBO80ca5jAkAIWMnN+Fpr4or+u1oAZDbiJqNHjxCKfAq9nMcKN
8ECRA70+BdpLmX5KIefR80BrdozHlOHfBvlyaTWP1+YkYvdo/mY3ahUnZgKS6I7kbVYn0BhxgyBi
G2gx4Yl9+R4jiP69etJqym7r1cSd65YQURMZlvpq1MUisjjfjIdHk+3W3qaY4y2rJUGwPf4xzyex
kOefR7l2YO6yZxiw5DJ0ArmPSAH3OSAUHHrwB+c9SoId7DSpKOOf+mt9/kcFi76ALlBc58D4D7La
0DZ7NssMgcgutl/Q5ETxM6w3AGC/C05zmFHKxEOUsHzu0M0DzElWhvAc4wg1uaZjVgfGC/pl5zAE
9Nkm0EAQLb2CGC3FMjxOE+My4weyiVF+sUqwIvgdyzUg4l8fwr6tTp5fuYZljTj08boT7QqAxruS
BBZ7BCGzZY8Px+W4MZXj/powp9y7As8oFpPZY4vcMmhigRTi/ocXrQeBm7KaHwMnsXXYotg9KE3u
UGbz9/LFGiKsFuLbAgMBAAGjVDBSMB0GA1UdDgQWBBTYdap3IO58YdL5khQHJ9qyGL3xxDALBgNV
HQ8EBAMCAYYwDAYDVR0TBAUwAwEB/zAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDANBgkqhkiG9w0B
AQsFAAOCAgEAr/ERTjCi09xd+jZgGlSPLeadq3WK9hLlIrRQHdcUJ79YSAQSkO97x580Owi+5Qji
k3RkQHLH4XdcKElz67ILzf5kbBhYA3bXy3kzaFqMSujzVg3Cg5oUSGXp8o6wQAIixcQbjOUPq3Uv
6PEMe94rLR7d3pJgSFTSpUTdu7Nu3hTZ5BVvgcEx/++mgsCZIEUe9h0zfOrNUUk/kzeNgc9jvL+n
18LttqHYormLU2pT7dUKBFbF/nZkxevBwPn7rD3KJFwq/gJaXPjhJpPtj2kRNqC4CLd7cXm2suv4
kn5qQlreOOXa3OO2fAPMHCeoSBX5dPWBK9RT1N9psNUhRuz8NfxKU3+5x1udPBxgM/gNlT/piyrq
jbxVqI1sP2eh3vG3ZXHXoeNbJWKnzcRa8ISYa4NHskeU9kPZ5QIhTNcaBlJka0CQ06uEaNa44e+N
xQFCWGssqaMJ2BKRl6gMhBUwLE4Ldw9Z5TgBXq5M58uC6lck/m5PlOl8HKykt8RqYed09MR8A5Uw
Ji+noV27el6EBMt0SlZsw+78mk+ieLI+UbnzxjqfLK/v/fc+mEV0FWbZjKehb5kwT947vyd/1GdK
divPOt3z4UrWNYtquzuaWW6FMyKFDk4CVvIe9pOV6t6mM9wMp6/GapNhvdXuWxrWQXjp7Wti0yBA

                        UUNvYcQM5e0=
                    </ds:X509Certificate></ds:X509Data></ds:KeyInfo><xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:CipherValue>kMV2tdn2AZxtTxe40BCjj2kXQdLOCnRyynsyIAlUOfbSBLiHLSMLBIZ1f8yqD9I8wN0IzuCugnSG+2DHThcLViSz6y39aUxGW0CcnymOlrsI0e1C7PGrFyQ6ke7ayRFCI+ffqxp0VDBfK9Q5fwHVNi9IXz09NDCn78UlEbtl2XAlRVY9wUvJoDJ33maNfqrrK3Isc6REuShcwWevcNjUtmjZgP1bHr4jSjIHZ8zms+Bv+cwUv8Ez5wDHJJe3inqIr/6iU7XCjfRD60p4dIgVmo2VtYCEKLhBE6xcKgJm7Bb16O2sycMhUB5t3YUxFdU7whj5KB7IFZRL+12TlhlzgjgVAqrjfLyGJVox90u1YakyX7cDd6uPtLO0bwLupB484BrLYLVOte2Ugx2S2le2e7degQxv/ri90CyN6C1gUKznGg6tH7AJ+1UyIA152mcLjYAj5zkryORIdg0p38uGN27llgf76y7O3Tv+gFs+8GycT7JQisciFp048X2iMtvPDGL/F15jwArDMoDw+95izZElqdzP4GKz/maZ0khPXMIeak+sLG9qKwWQETeyKTSbQbXAMdfT0GQqgbuxahS4DMmDBGXbIHOEEDfXFOqsPso6kicRsTvTkEvDVDbhVAjNu79kJBvcPxKgv9wLhJTqbu6wYDtKeEM56+
                    AeLIBXOpE=
                </xenc:CipherValue></xenc:CipherData><xenc:ReferenceList><xenc:DataReference 
                    URI="#_24bd7d84448b12589a8b12a697f44fa7"/></xenc:ReferenceList></xenc:EncryptedKey></saml2:EncryptedAssertion></saml2p:Response>

Important Attributes in the SAML Response:

  • Destination: The URL indicates where to send the response, typically the ServiceNow instance URL.
  • ID: The unique identifier of the SAML response.
  • InResponseTo: Matches the request ID from the original SAML request.
  • IssueInstant: The timestamp indicates when the response was issued.
  • Issuer: Identifies the IdP that issued the response.
  • Status: Contains the status code indicating the success or failure of the authentication.
  • Assertion: Contains the actual authentication statement and attributes about the user.
  • Signature: Includes cryptographic information to ensure the authenticity and integrity of the response. This element has several key components:
    • SignedInfo: This section includes the canonicalized (standardized) form of the signed data. It contains information on the signature method and references.
    • DigestValue: A hash of the referenced data ensures that the data has not been altered.
    • SignatureValue: The actual digital signature generated by encrypting the hash of the SignedInfo element with the IdP’s private key.

By understanding these attributes, you can better comprehend how ServiceNow processes and validates the SAML response to authenticate users.

How ServiceNow Processes the SAML Response

  1. Retrieve the Stored Request ID: ServiceNow retrieves the stored request ID from the session to ensure it matches the InResponseTo attribute in the SAML response.
  2. Validate the Signature: ServiceNow confirms the response’s authenticity and ensures it has not been tampered with by validating the digital signature. The signature verification process involves checking the <ds:Signature> tag, which contains the signed information and the signature value. The system uses the public key from the IdP’s certificate to verify the signature against the signed information, ensuring the integrity and authenticity of the response. Refer to the cryptography article to understand how it works.
  3. Check the Status: ServiceNow checks the status code to determine if the authentication was successful.
  4. Extract User Information: ServiceNow extracts user information from the assertion to log the user in or provision a new user account if necessary.
  5. Authenticate User: ServiceNow authenticates the user using the extracted information. If the user doesn’t exist, it may provision a new user account.
  6. Log User In: If the authentication is successful, ServiceNow logs the user into the system. If you provide a relay state, the system redirects the user to that page after a successful login.
  7. Handle Errors: If any errors occur during the process, ServiceNow handles them appropriately, providing error messages or logging details for troubleshooting.

SSO Request and Response Without Encryption

In this section, we will see how SSO requests and responses work without encryption.

To disable encryption and signing in the SAML response from Okta or your IDP, you need to do two things:

First, update the Encryption and Signing settings of the identity provider in ServiceNow. Uncheck the “Encrypt Assertion” checkbox. This change tells ServiceNow that the SAML response is not encrypted or signed.

It is important to note that we will keep the “Sign AuthnRequest” checkbox checked. This allows us to use the same SSO login URL we created earlier. Remember, enabling encryption and signing is the proper way to set up SSO. We are disabling these features here to better understand how SSO works without them.

Second, update the settings in Okta to disable encryption and signing of the assertion.

Build the login URL and send the request to IDP

Let’s build the login URL and send the request to the IDP. We will use the same URL template discussed earlier. As a quick recap, the URL template looks like this:

<IDP-SSO-URL>?SAMLRequest=<SAML-REQUEST-URL-ENCODED>&SigAlg=<SIG-ALG>&Signature=<URL-ENCODED-SIGN>&RelayState=<URL-ENCODED-RELAY>

Since we are signing the SSO XML request, we can use the URL we generated before.

If we had unchecked “Sign AuthnRequest” in the Identity Provider record, we could skip the SigAlg and Signature URL parameters. Additionally, you need to change the settings in Okta to let Okta know that we won’t be sending signed SSO login requests.

Here is the final SSO login URL:

https://dev-06037387.okta.com/app/dev-06037387_servicenowgurudemo_1/exkhbgik0lUIiSbJO5d7/sso/saml?SAMLRequest=hVLBcoIwEP0VJncgATWSEWasHmrHVkewh16cAClmhIRmg%2B3nV9HO6MUed97bt7vv7QR4Uwctm3Z2rzbiqxNgnZ%2BmVsAuSIw6o5jmIIEp3ghgtmDp9HXJAg%2Bz1mirC10jZwogjJVazbSCrhEmFeYoC7HdLGO0t7YF5vulOAZkFJGRBxfUVfrbK3TjK35seSW8UiNnftpBKn4Wu2t18QiHNBxTTx8s79t4294hu6vuSbbqTFeKRu%2BIL34O%2B7ySB1xvFzLNX1bDkvoA2j%2BfiJzFPEbp26ygPBJFHmEeRnxIhzTPeSg%2By4DnBJecnogAnVgosFzZGAU4GLiYuniQEcxIwAbEI3j8gZz11ZUnqUqpqscW5hcSsOcsW7vrVZoh510Y6K8%2FEVAy6ZNg%2FXRzG85jYf6XCEr%2B9X%2Fi385IruX9WyS%2F&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=GokmsDs%2Fqv7RvWy%2FuJbQ6GhZBnnnpKevpqgkjk%2FfdgW%2BQ1dND9%2BF9A0yUb1sRBHXlLgrkIqQiC5LAy0nuqcxllH1PJ%2F1UMVJd6lOg6skH8WCXSZbjTpbixN%2BIpgSszVUAypZ%2Bj8DuhKxGs0CLfIHgDafPbAz5O7OwI1w1L%2FZ4BQfTTV%2BayBwvWOHpc1QGJDcuqhV3AecX%2Ff8MHh5RGQ9rgCyfOk5tmDSXOgl1pEh3%2FQDIDaNKVNPPmVj8qIEKOtn8OH0T3KMTqPOivYWnyn2TxcfdZB1z%2BMYQUvMQPqbxRrFyJxo7TX6FNAqam680UgmkKvdbc6bMTtaz8wlAqiXWIvWq8P5MgPiyTcGTSe33591NT6HCNcm9FxrpWD0NNQFC%2Fn2aT0gM8yilp77IwNtE6in8X5IxHq8FHXO6XD%2FaZk8b%2Fqd4ce%2FGKe4mZ6TCkCYlWiglWV2v1BlvaXwdM8kAbAimazC1oeAmRiDJ6GJR553pkEqDjGL5z9u78tBQoiaTzQMs92DK5Z%2B9uPO0oxkvB%2FNAFP7CFExXz2JKlO%2B8wNrdoecDX%2F4duZIAGCKihQwkcqwjE7VXzxM8x8rH1XbLI8telN%2FlMkMiza2T3SJSTGpp11ojfAKcDXdSdawbLnnyYhzEK6r2g9sI0zIdp%2BoTQ5VJm5oQAJ642SQseHYjDY%3D&RelayState=https%3A%2F%2Fdev216916.service-now.com%2Fnavpage.do

SAML Response XML Example

Here is an example of a SAML Response XML captured during the process:

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response 
    Destination="https://dev216916.service-now.com/navpage.do" 
    ID="id18313862044489861863811899" 
    InResponseTo="SNC8d80819049bcd8752c34b09f6067c431" 
    IssueInstant="2024-07-13T09:39:41.088Z" 
    Version="2.0" 
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer 
        Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" 
        xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exkhbgik0lUIiSbJO5d7
    </saml2:Issuer>
    <saml2p:Status>
        <saml2p:StatusCode 
            Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </saml2p:Status>
    <saml2:Assertion 
        ID="id18313862046302591638818707" 
        IssueInstant="2024-07-13T09:39:41.088Z" 
        Version="2.0" 
        xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
        <saml2:Issuer 
            Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exkhbgik0lUIiSbJO5d7
        </saml2:Issuer>
        <saml2:Subject>
            <saml2:NameID 
                Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">harry.potter@gmail.com
            </saml2:NameID>
            <saml2:SubjectConfirmation 
                Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml2:SubjectConfirmationData 
                    InResponseTo="SNC8d80819049bcd8752c34b09f6067c431" 
                    NotOnOrAfter="2024-07-13T09:44:41.088Z" 
                    Recipient="https://dev216916.service-now.com/navpage.do"/>
            </saml2:SubjectConfirmation>
        </saml2:Subject>
        <saml2:Conditions 
            NotBefore="2024-07-13T09:34:41.088Z" 
            NotOnOrAfter="2024-07-13T09:44:41.088Z">
            <saml2:AudienceRestriction>
                <saml2:Audience>https://dev216916.service-now.com</saml2:Audience>
            </saml2:AudienceRestriction>
        </saml2:Conditions>
        <saml2:AuthnStatement 
            AuthnInstant="2024-07-13T09:39:41.088Z" 
            SessionIndex="SNC8d80819049bcd8752c34b09f6067c431">
            <saml2:AuthnContext>
                <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
            </saml2:AuthnContext>
        </saml2:AuthnStatement>
        <saml2:AttributeStatement>
            <saml2:Attribute 
                Name="FirstName" 
                NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
                <saml2:AttributeValue 
                    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                    xsi:type="xs:string">Harry
                </saml2:AttributeValue>
            </saml2:Attribute>
            <saml2:Attribute 
                Name="LastName" 
                NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
                <saml2:AttributeValue 
                    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                    xsi:type="xs:string">Potter
                </saml2:AttributeValue>
            </saml2:Attribute>
            <saml2:Attribute 
                Name="Email" 
                NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
                <saml2:AttributeValue 
                    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                    xsi:type="xs:string">harry.potter@gmail.com
                </saml2:AttributeValue>
            </saml2:Attribute>
        </saml2:AttributeStatement>
    </saml2:Assertion>
</saml2p:Response>

Understanding this response is simpler without encryption and signing. Let’s explore some of the key elements below.

Description of the SAML Response XML

  1. Response Element: This is the root element containing the entire SAML response. Key attributes include:
    • Destination: The URL where the response is sent, typically the ServiceNow instance URL.
    • ID: A unique identifier for the response.
    • InResponseTo: The ID of the SAML request this response addresses.
    • IssueInstant: The timestamp when the response was issued.
    • Version: The SAML version.
  2. Issuer Element: Identifies the entity that issued the response, in this case, Okta.
  3. Status Element: Contains the status code, indicating the success of the authentication process.
  4. Assertion Element: Contains the actual SAML assertion, which includes several child elements:
    • Issuer: Identifies the entity that issued the assertion.
    • Subject: Contains information about the authenticated user, including:
      • NameID: The user’s identifier, typically an email address.
      • SubjectConfirmation: Details for confirming the subject’s identity.
    • Conditions: Specifies the conditions under which the assertion is valid, including:
      • AudienceRestriction: Defines the audience for the assertion, usually the ServiceNow instance.
    • AuthnStatement: Provides details about the authentication event, including:
      • AuthnInstant: The time when the authentication occurred.
      • AuthnContext: The context of the authentication, such as password-protected transport.
    • AttributeStatement: Contains user attributes, such as FirstName, LastName, and Email.

This breakdown of the SAML Response XML should help you understand the structure and elements involved in a typical SAML response.

SAML Logout

In this section, we will not cover the details of SAML Logout extensively as it follows a similar process to the SAML login requests. The primary difference lies in the type of request being made—logout instead of login. For those already familiar with SAML login, the logout process will appear quite analogous.

SAML Logout URL Template and Explanation

The SAML Logout URL follows a specific template to initiate a logout request. Here’s how it looks:

<IDP-Logout-URL>?SAMLRequest=<SAML-LOGOUT-REQUEST-URL-ENCODED>&RelayState=<URL-ENCODED-RELAY>&SigAlg=<SIGNATURE-ALGORITHM>&Signature=<URL-ENCODED-SIGNATURE>

Explanation:

  • IDP-Logout-URL: The URL of the Identity Provider (IDP) that handles the logout request.
  • SAMLRequest: The URL-encoded SAML logout request.
  • RelayState: Optional parameter to maintain the state between the ServiceNow instance and the IDP, often used to redirect the user back to a specific page after logout.
  • SigAlg: The algorithm used to sign the SAML request (e.g., RSA-SHA256).
  • Signature: The URL-encoded digital signature of the SAML request.

SAML Logout XML Template

The SAML Logout XML contains the necessary information for the logout process. Here’s a basic template:

<samlp:LogoutRequest 
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" 
    ID="id123456789" 
    Version="2.0" 
    IssueInstant="2024-07-04T12:01:31.372Z" 
    Destination="https://idp.example.com/logout">
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://dev216916.service-now.com</saml:Issuer>
    <samlp:NameID>username@example.com</samlp:NameID>
    <samlp:SessionIndex>session12345</samlp:SessionIndex>
</samlp:LogoutRequest>

How the Logout Works

When a user initiates a logout, the ServiceNow instance sends a logout request to the IDP using the Logout URL template. The process is similar to the SAML Login Request, with the main difference being the SAML Logout XML sent in the URL.

Here’s a brief overview:

  • User Initiates Logout: The user clicks the logout button in ServiceNow.
  • ServiceNow Sends Logout Request: ServiceNow creates a SAML Logout Request and sends it to the IDP using the user’s browser.
  • IDP Processes Request: The IDP receives the logout request and processes it.
  • IDP Sends Logout Response: The IDP sends a SAML Logout Response back to ServiceNow.

We won’t dive into the details of handling the request and response, as they are similar to the SAML Login Request process.

Conclusion

Understanding how SAML 2.0 SSO works in ServiceNow is essential for developers to ensure secure and seamless user authentication. In a world where privacy and security are of utmost importance, grasping the principles of encryption and signing is crucial. This knowledge not only aids in troubleshooting and optimizing SSO implementations but also enhances the ability to secure data transmission and implement robust authentication mechanisms. Mastering SAML 2.0 SSO equips developers with the skills needed to navigate and implement various security protocols in ServiceNow, contributing to a more secure and efficient environment.

Next Steps: OpenID Connect

To further enhance your understanding of authentication and security in ServiceNow, keep an eye out for our upcoming article on OpenID Connect. OpenID Connect offers an additional layer of security and flexibility for user authentication, making it a valuable next step in mastering identity management within ServiceNow.

The post Demystifying SAML 2.0 Single Sign-On in ServiceNow appeared first on ServiceNow Guru.

]]>
Demystifying Cryptography in ServiceNow: A Comprehensive Guide to Secure Data Transmission https://servicenowguru.com/system-definition/demystifying-cryptography-servicenow/ https://servicenowguru.com/system-definition/demystifying-cryptography-servicenow/#comments Mon, 10 Jun 2024 14:03:48 +0000 https://servicenowguru.com/?p=15397 This article is the 1st in a series of posts that aim to demystify the complex world of cryptography within ServiceNow. In this installment, we dive into the foundational topics of URL encoding, base64 encoding, hashing, symmetric and asymmetric encryption, hybrid encryption, and digital signatures. These cryptographic principles are essential for understanding the more advanced

The post Demystifying Cryptography in ServiceNow: A Comprehensive Guide to Secure Data Transmission appeared first on ServiceNow Guru.

]]>
This article is the 1st in a series of posts that aim to demystify the complex world of cryptography within ServiceNow. In this installment, we dive into the foundational topics of URL encoding, base64 encoding, hashing, symmetric and asymmetric encryption, hybrid encryption, and digital signatures.

These cryptographic principles are essential for understanding the more advanced topics we will explore in subsequent articles, including a detailed look at SAML 2.0 in our second piece. This series aims to provide both newcomers and seasoned developers with a thorough understanding of cryptographic techniques used in ServiceNow.

Now, let’s begin our journey by exploring the fundamental concept of URL encoding.

Understanding URL Encoding

URL encoding is important in web development because it ensures that special characters in URLs are properly handled for internet transmission. Let’s break down the basics of URL encoding and its importance.

Why URL Encoding is Necessary?

When you construct a URL, you can’t include certain characters directly, such as spaces, question marks (?), and equals signs (=). These characters have different purposes within the URL syntax. To include them in the URL’s parameters and values, you need to encode them into a specific format.

The URL Encoding Process

URL encoding changes special characters into a text-based format so URLs can be safely sent and understood by web servers and browsers.

Example

Consider the following text that we want to include as part of a URL: “Hello World?“.  Through the URL encoding algorithm, this text is transformed into the following encoded format: “Hello%20World%3F
Here, the space is encoded as “%20“, and the question mark is encoded as “%3F“.

 

Not Encryption, but Transformation:

It’s important to understand that URL encoding is not a form of encryption. Its purpose is to convert text into a format that can be safely included in a URL, ensuring proper transmission rather than hiding the data.

Usage in ServiceNow

  1. REST API Requests: ServiceNow REST APIs often need URL encoding to handle special characters in request parameters, query strings, or resource identifiers (specific records, tables, or endpoints within the ServiceNow instance). URL encoding ensures the data in API requests is correctly formatted and interpreted by the ServiceNow instance.
  2. Integration URLs: URLs used in ServiceNow integrations, such as inbound or outbound web service integrations, may require URL encoding to manage special characters in endpoint URLs or request payloads. This encoding helps ensure smooth data exchange between ServiceNow and external systems.
  3. UI Actions and Script URLs: When setting up UI actions or script URLs in ServiceNow, URL encoding may be necessary to encode dynamic parameters or values containing special characters. This ensures that dynamically generated URLs in UI actions or scripts are correctly formatted and interpreted by the platform.

After understanding the importance of URL encoding, let’s shift our focus to another essential encoding technique utilized in ServiceNow: Base64 encoding.

Base64 Encoding in ServiceNow

Why Base64 Encoding is Necessary?

In ServiceNow, Base64 encoding addresses the need to convert binary data, such as images, compressed data, or compiled data, into a textual representation. This conversion enables the embedding of binary data into various text-based formats, such as HTML, CSS, or XML files, facilitating seamless integration and transmission across different systems and platforms.

The Base64 Encoding Process

Base64 encoding converts binary data into a text-based format using a specific encoding algorithm. This process transforms binary data into a set of ASCII characters, allowing you to safely transmit it over protocols that only support text data. Conversely, Base64 decoding reverses this process, converting the encoded text back into its original binary form.

Example

Imagine a scenario where a ServiceNow application needs to transmit binary data, such as an image file, over an HTTP request. Before transmission, the binary data undergoes Base64 encoding to convert it into a text-based representation. This encoded data can then be included in the HTTP request payload. Upon receiving the request, the ServiceNow instance decodes the Base64 encoded data to reconstruct the original binary file.

Base64 Encoding & Decoding Scripts

// Base64 Encoding Example
var binaryData = new GlideStringUtil();
var base64EncodedData = binaryData.base64Encode('Hello World'); // Base64 encode data
gs.info('Base64 Encoded Data: ' + base64EncodedData); // Log Base64 encoded data// Base64 Decoding Example
var base64EncodedData = 'SGVsbG8gV29ybGQ/'; // Base64 encoded data
var binaryData = GlideStringUtil.base64Decode(base64EncodedData); // Decode Base64 data
gs.info('Decoded Binary Data: ' + binaryData); // Log decoded binary data

Usage in ServiceNow

  1. Attachment Handling: When you upload file attachments to a ServiceNow record, ServiceNow converts the files to Base64 format before storing or sending them using REST. When you download these attachments, ServiceNow changes the Base64 data back to the original file format.
  2. Integration Payloads: In integrations between ServiceNow and external systems, you use Base64 encoding to send binary data, like images or documents, over HTTP requests or other communication methods. This ensures smooth data exchange between ServiceNow and other platforms.

Also, you often send binary data through HTTP POST requests, especially in authentication systems like SAML or OpenID Connect. In these cases, you usually convert the binary data to Base64 format before sending it via HTTP POST. If you use the Base64-encoded data in a URL, you also need to URL encode it. This process ensures that binary data is securely and reliably transmitted over text-based protocols.

Now that we’ve explored the essential encoding techniques used in ServiceNow, let’s delve into the world of hashing, a fundamental cryptographic process that ensures data integrity and security.

Hashing in Cryptography

In cryptography, hashing stands as a fundamental concept, forming the foundation of many security protocols and mechanisms. At its core, a cryptographic hashing function transforms any input data into a fixed-size text representation known as a hash or digest using hashing algorithms like SHA-256/512 or MD5. This is an irreversible process and it ensures data integrity and uniqueness.

Applications of Hashing

  1. Password Security: When storing passwords in a database, systems use hashing algorithms like SHA-256 or SHA-512 to hash the password along with any optional salt (a prefix or a postfix). To authenticate logins, the system hashes the password entered by the user using the same algorithm and compares it with the hashed password stored in the database. This ensures passwords are securely stored and enables secure logins.
  2. Data Integrity Verification: You can also hash files to generate a digest. The hashed value or digest of the file will not change unless someone tampers with the file. This helps verify data integrity during transmission.
  3. Message Authentication: Hashing ensures that messages are authentic and have maintained their integrity during transmission. In authentication systems, hashes are used to verify that the message has not been changed or tampered with.

Hashing in ServiceNow

ServiceNow prioritizes data security and integrity by using hashing algorithms like SHA-256 and SHA-512 to strengthen authentication and verify data integrity.

Hashing is also important in protocols like SAML 2.0 for checking data integrity and message authentication. We will discuss this more in the next article on SAML 2.0.

Unlocking Encryption: Key-Based Symmetric and Asymmetric Techniques

The primary goal of encryption is to safeguard confidentiality, ensuring that only intended recipients can understand the transmitted data.

In this article, we will delve into key-based encryption—a method extensively utilized in contemporary digital environments, including by platforms like ServiceNow.

We will explore two predominant types of encryption: symmetric and asymmetric, each with its unique advantages and challenges. Due to these characteristics, the industry has developed hybrid encryption, which combines the strengths of both symmetric and asymmetric methods. By understanding these three encryption types, we can better appreciate why ServiceNow adopts them and how they can help address challenges that may arise when dealing with this topic within the platform.

Let’s now explore each of them.

Symmetric Encryption: A Real-Time Approach

In symmetric encryption, you use a single key for both encrypting and decrypting data. This method is fast, uses less CPU power, and keeps the encrypted text (cipher) the same size as the original text. Such efficiency makes symmetric encryption best for applications where real-time encryption and decryption are crucial, such as secure communication channels (e.g., VPNs) or data streaming services (e.g., Netflix).

However, symmetric encryption presents a significant challenge: securely sharing the encryption key between the sender and the recipient. Without a secure mechanism for key distribution, the integrity of encrypted communication may be compromised. This necessity highlights the importance of encryption protocols and the ongoing need for robust security measures, including key management systems and secure channels for key exchange.

One commonly used algorithm in symmetric encryption is the Advanced Encryption Standard (AES). AES allows for various key lengths, such as AES-128, AES-192, and AES-256, with ServiceNow predominantly using AES-128 due to its balance between security and efficiency

Strengths of Symmetric Encryption:

  • Faster processing compared to asymmetric encryption.
  • Maintains the size of the encrypted text equal to the original plaintext.
  • Ideal for real-time encryption and decryption scenarios.

Weaknesses of Symmetric Encryption:

  • Requires secure distribution of encryption keys.
  • Vulnerable to key interception or compromise.
  • Limited scalability for large-scale encryption operations.

Example: Symmetric Encryption

In the context of symmetric encryption, let’s consider a scenario involving two users: Alice (the sender) and Bob (the recipient). They communicate over the internet, represented by a cloud icon, and exchange sensitive information securely using symmetric encryption.

 

Asymmetric Encryption: Securing Communications with Keys

To address the limitations of symmetric encryption, especially the challenge of securely sharing the secret key, cryptographers developed asymmetric encryption, also known as public-key encryption. This method uses two keys for each participant: a private key and a public key. Asymmetric encryption enhances security by allowing secure communication without the need for exchanging secret keys beforehand.

In asymmetric encryption, each participant generates a unique pair of keys: a private key and a public key. The private key is kept secure by the owner and never shared, acting as a digital signature to confirm the owner’s identity and authenticity. The public key, on the other hand, is shared freely, allowing others to send secure communications without compromising security.

The RSA algorithm is the most widely used method in asymmetric encryption. It involves a private key and a public key. Data encrypted with the public key can only be decrypted with the corresponding private key, ensuring confidentiality and security. Likewise, data signed with the private key can be verified with the public key, guaranteeing authenticity and integrity.

Now, let’s illustrate how asymmetric encryption works in practice with a scenario involving Alice and Bob:

Example: Secure Email Communication

Alice, a business executive, needs to send a confidential email containing financial reports to Bob, her colleague. To ensure the privacy and integrity of the email contents, both Alice and Bob utilize asymmetric encryption:

  • Key Generation: Both Alice and Bob generate their own pairs of asymmetric encryption keys: a Private key and a corresponding Public key. Each individual keeps their Private key securely stored and never shares it with anyone, while freely distributing their Public key to others.
  • Encryption: Before sending the email, Alice encrypts the contents using Bob’s Public key. This process transforms the plaintext email into ciphertext, ensuring that only Bob, with his corresponding Private key, can decrypt and read the message. The encrypted email is then sent to Bob via the email service provider.
  • Reception by Bob: Upon receiving the encrypted email, Bob uses his Private key to decrypt the contents. Only Bob’s Private key, known only to him, can successfully decrypt the ciphertext, revealing the original plaintext email.
  • Response: If Bob needs to respond to Alice’s email, he can encrypt his reply using Alice’s Public key. This ensures that only Alice, with her corresponding Private key, can decrypt and read the message, maintaining the security of their communication.

By leveraging asymmetric encryption with RSA keys, Alice and Bob can securely exchange sensitive information via email, confident in the confidentiality, authenticity, and integrity of their communication.

In practical implementations, the distribution and verification of public keys are facilitated by digital certificates issued by trusted Certificate Authorities (CAs). These certificates, conforming to the X.509 standard, bind public keys to identities, providing a reliable means of authentication and trust in the digital world.

Strengths of Asymmetric Encryption:

  • Private key is never shared, enhancing security.
  • Facilitates secure digital signatures and key exchange protocols.
  • Enables secure communication over insecure channels without pre-shared keys.

Weaknesses of Asymmetric Encryption:

  • Increased computational overhead compared to symmetric encryption.
  • Larger key sizes lead to larger ciphertexts and slower processing speeds.
  • Key management and distribution can pose logistical challenges in large-scale deployments.

Through asymmetric encryption with individual pairs of asymmetric encryption keys, Alice and Bob can securely exchange sensitive information via email, protecting the confidentiality, authenticity, and integrity of their email correspondence.

Hybrid Encryption: Combining the Best of Both Worlds

While symmetric encryption excels in real-time encryption and decryption scenarios, and asymmetric encryption provides secure key exchange, both methods have their limitations. Symmetric encryption requires a secure channel for key distribution, while asymmetric encryption introduces computational overhead. Hybrid encryption combines the strengths of both approaches, maximizing security in data transmission.

In hybrid encryption, symmetric encryption encrypts the actual data, while asymmetric encryption securely exchanges the symmetric key. This approach minimizes computational overhead and ensures secure key distribution, making it ideal for applications where both efficiency and security are important.

Let’s delve deeper into how hybrid encryption works through an example of secure email communication between Alice and Bob:

Example: Secure Email Communication

Alice, needing to send a large financial report to Bob, initiates the hybrid encryption process:

  • Key Generation: Alice generates a random secret key and uses symmetric encryption (e.g., AES 256) to encrypt the email contents, including any attachments.
  • Encryption of Secret Key: Alice encrypts the random secret key using Bob’s public key, ensuring that only Bob can decrypt it.
  • Secure Transfer: Alice sends the AES-encrypted data and the asymmetrically encrypted secret key to Bob through the email service provider.
  • Reception by Bob: Upon receiving the encrypted data and secret key, Bob decrypts the asymmetrically encrypted key using his private key, obtaining the original secret key. Finally, Bob uses the decrypted secret key to decrypt the AES-encrypted data, recovering the plaintext email and any attachments.

Applications automatically handle encryption and decryption using libraries. For example, when generating a SAML request, ServiceNow generates encrypted data and key information using packages, stores them in XML format, and sends them using HTTP post. ServiceNow also base64 encodes these encrypted pieces to keep the data intact during transmission.

Hybrid encryption combines the strengths of both symmetric and asymmetric methods. This approach ensures secure and efficient data exchange, providing strong protection for data as it travels.

Digital Signatures: Ensuring Data Integrity and Authenticity

In addition to encryption, digital signatures play a crucial role in securing data transmission, providing integrity and authentication. While encryption safeguards the confidentiality of data, digital signatures verify the origin and integrity of the message.

Let’s delve into how digital signatures work and how they complement encryption:

Utilizing Hashing Algorithms: Digital signatures leverage hashing algorithms to condense messages into smaller, fixed-size representations, ensuring efficient processing. These algorithms generate a unique fingerprint or digest of the original message, preserving its integrity.

Signature Generation: Suppose Alice intends to send a message to Bob. Alice first generates the message and then applies a hashing algorithm to produce a digest of the message. Next, she encrypts this digest using her private key, creating the signature. This signature serves as proof of authenticity and integrity for the message.

Signature Verification: Upon receiving the message and signature, Bob employs Alice’s public key to decrypt the signature, revealing the original digest. Independently, Bob calculates a hash of the received message. If the calculated hash matches the decrypted digest, two critical aspects are verified:

  • Integrity: Any alteration to the message would result in a different hash, ensuring that the message remains unchanged since Alice signed it.
  • Authentication: Since only Alice’s private key could have generated the signature, decrypting it with Alice’s public key confirms its authenticity. This authentication mechanism proves that Alice is the true sender of the message.

Application of Signatures: While we often associate signatures with messages, they extend beyond text-based communication. Signatures can authenticate various data forms, such as certificates, software, emails, and more. The essence of signatures lies in providing both integrity and authentication, irrespective of the data type.

Let’s illustrate the digital signature process using Alice and Bob:

Example: Signing a Data Message

Imagine Alice needs to sign a critical document or data message and send it to Bob securely. Here’s how digital signatures come into play:

  • Message Creation: Alice prepares the document or data message that needs to be signed. It could be any digital content, such as a contract, a software update, or an important report.
  • Signature Generation by Alice: Before sending the data message, Alice computes a hash (digest) of the message using a hashing algorithm like SHA256. This hash serves as a unique representation of the content. Alice then encrypts this hash using her private key, generating the digital signature.
  • Sending the Signed Message: Alice sends the data message along with the digital signature to Bob. The message contains both the original content and the attached signature.
  • Verification by Bob: Upon receiving the data message, Bob extracts the message and the attached digital signature. Using Alice’s public key, which he previously obtained or can access from a trusted source, Bob decrypts the digital signature, obtaining the hash of the original message.
  • Hash Calculation by Bob: Independently, Bob calculates the hash of the received message using the same hashing algorithm (SHA256). This calculation results in a hash value.
  • Comparing Hashes: Bob compares the hash value obtained from his calculation with the decrypted hash obtained from Alice’s digital signature. If the two hash values match, Bob can be confident that the message has not been altered since Alice signed it. This verifies the integrity of the data message.
  • Authentication: Additionally, since only Alice’s private key could have produced the digital signature that Bob successfully decrypted with Alice’s public key, Bob can authenticate that the message indeed originated from Alice.

By using digital signatures in data transmission, Alice and Bob can ensure their communication is both genuine and intact, adding more security beyond encryption.

This example shows how digital signatures make data exchange safer by keeping messages unchanged and verifying the sender’s identity.

While this example only uses digital signatures without encryption, combining both techniques often boosts security. For instance, in SAML scenarios, Alice can first sign the data with her private key, then encrypt it with Bob’s public key before sending it. Bob would then decrypt the message with his private key and verify its origin with Alice’s public key.

This hybrid method, mixing digital signatures and encryption, fully protects sensitive data during transmission, ensuring both integrity and authenticity. We’ll explore these scenarios more in our next article on SAML 2.0.

Conclusion

In this article, we explored the essential cryptographic technologies necessary for securing applications within ServiceNow. Understanding these principles sets the stage for our next discussion on SAML 2.0, where we’ll dive deeper into how these cryptographic measures are applied in implementing secure Single Sign-On (SSO) solutions. Stay tuned for more advanced topics that will further enhance your security posture in ServiceNow.

The post Demystifying Cryptography in ServiceNow: A Comprehensive Guide to Secure Data Transmission appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-definition/demystifying-cryptography-servicenow/feed/ 1