REST over NTLM - solution proposed
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-09-2022 01:36 PM
After spending some time searching on the forums for something like this and coming up empty, I did some trial and error on my own and found something that works. I don't know if others will find this useful, but after some internal demos to colleagues, they suggested I post on the forums.
So, as we know, setting up REST Messages to invoke external APIs via Basic Authentication or OAUTH is well-documented and well supported. However, we had an integration in our environment that required NTLM authentication, which isn't natively supported in ServiceNow.
However, Flow Designer makes it very easy to create an Action that runs a Powershell Script and returns the results of that script to the Flow in the outputs, so, we took advantage of how easy it is to use NTLM authentication in Powershell and how easy it is to write Powershell from inside a ServiceNow Flow Action, and came up with something that has been working for us. You do need to have the Powershell plugin for the IntegrationHub for this to work.
Credentials
Though we're not using Basic Auth, NTLM authentication is similar in that it wants a username and password. So, we started by creating a Basic Auth Credential (basic_auth_credentials) that provide the username and password we'll need to use to invoke our target API. We don't want to create an alias, because we don't want to use these credentials to log into a target host - we're just trying to safely and securely store the credentials we're going to use later.
Flow Designer
Then, we need to create our new Action in Flow Designer. We called ours 'NTLM REST via Powershell'
Inputs
We created input variables for the following parameters we will use in our Flow:
Label | Name | Type |
midserver | midserver | Reference.Mid Server |
basic_auth_credentials | basic_auth_credentials | Reference.Basic Auth Credentials |
uri | uri | String |
resource | resource | String |
parameters | parameters | String |
Powershell Step
Once you have the parameters configured, insert a Powershell step.
There are two sections in the Powershell Step - the first is Connection Details, and the second is Script Details
Connection Details
So, normally, the way this step would work, you'd configure a connection, and the midserver that gets selected would get used to connect to the Host specified in the connection details (either explicitly set, or determined by your credential alias), and then would try to run this Powershell script on THAT host. We don't want to do that. What we want to do is tell the system to run this Powershell script on OUR midserver; the _script_ is doing the work to connect to a target URI, so our connection parameters are really about making sure that the action does NOT try to connect to some other host to run.
Connection: Define connection inline
Credential Alias: <leave blank>
Host: 120.0.0.1
Port: <leave blank>
MID Selection: Specific MID Server
MID Server: action>midserver (using the input variable to determine the mid). You may not need this in your system. We have certain midservers that can reach out to the internet, to hosts on our domains, or to other specific domains. It was easier for us to manually choose midserver that would always work, rather than trust the autoselection.
Remoting Type: Run on a MID Server or have your script establish a remote session
Script Details
Script Type: Inline Script
Input Variables -
Name | Value |
resource | action>resource (input parameters) |
user_name | action>basic_auth_credentials>User name (input parameters) |
pass_word | action>basic_auth_credentials>Password (input parameters) |
params | action>parameters (input parameters) |
uri | action>uri (input parameters |
Command -
This is the Powershell script that does the real work, just using the parameters we're passing in. We are kind of cheating, because there is a $creds variable that gets passed to the script, but we don't want to use those. We're NOT using a credential alias because we don't want Powershell to try to log into that host - we want to have our script connect to that host, so we have to instantiate a new Powershell Credential object in our script, then pass that to the Invoke-RestMethod function
$pwd = ConvertTo-SecureString $pass_word -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($user_name,$pwd)
$endpoint = $uri+$resource+$params
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Accept', 'application/json')
$method = 'get'
$response = Invoke-RestMethod -Headers $headers -Method $method -Uri $endpoint -Credential
$response | ConvertTo-Json -Compress
|
And that's it. You can change that Invoke-RestMethod to a try - catch block and return additional information, but if it errors out, those errors get returned already to the Action. But if you want to handle those more gracefully, you can change modify that script and have it send the output as Raw text, or into separated objects (headers, body, etc.)
But this met our need, and others might find it useful as well.
- Labels:
-
Integrations
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-24-2022 12:47 PM
Thank you Jacob, but I don't see anything about NTLM in your code. Do you need to specify some NTLM option?
I used to use curl command to get the security token like this:
> curl -s -i --ntlm --user 'name:pass' 'some url'
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-08-2023 08:49 AM
Is the Host in the Connection details the midserver IP address? I'm trying to implement this and am getting "coud not create SSL/TSL secure channel' message.
Thanks

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
01-02-2024 04:47 AM
Add this to the beginning of your PS script to solve the SSL/TLS issue:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-31-2024 11:21 AM
Change your Powershell script to this
param (
$url = ${uri},
$username = ${user_name},
$password = ${pass_word},
$domain = 'example.com'
)
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential("$domain\$username", $secpasswd)
try {
$response = Invoke-RestMethod -Uri $url -Method Get -Credential $credentials
$responseContent = $response | ConvertTo-Json
Write-Output $responseContent
} catch {
Write-Output $_.Exception.Message
}