The documentation for ServiceNow’s SAML setup is the best that it has ever been. More and more customers are able to set up SAML correctly without having to engage outside help. That being said, what happens when you set up SAML and things just aren’t working out correctly?
When debugging SAML issues in ServiceNow, there are two things I recommend:
1. Use the Debug Log statements in ServiceNow
2. Use a network tracer such as those built into Chrome & Firefox, or Fiddler for Windows users.
This article covers the first recommended action, following the Debug Log statements inside ServiceNow.
Enabling and Viewing Debug Logging
First, you will need to make sure you have Debug Logging enabled for your SAML plugin. This can be done by browsing to the properties page and checked the Debug Logging checkbox.
This will ensure that the SAML debug statements will be logged to your instance’s System Log.
Now, to browse your System Log, simply go to “System Logs -> All”. I like to sort my logs on creation date where the create time on the filter for the log is after the last statement before I attempt to do a SAML login.
Typical Log Statements
The following is typical log output for a successful SAML authentication:
This line just shows the SAML processing URL (the one that the IdP will send the Response to when it is done) and also the calculated base URL of the instance for use later on in the script.
1 | Stripping down the serviceURL: https://myinstance.service-now.com/navpage.do to a base URL of: https://myinstance.service-now.com |
Now, in the case of this example, we were using deep linking. This means that we clicked on a non-home page link an after authentication we want to be redirected to that specific page. In order for SAML to trigger on that, the url needs to use “nav_to.do”. This is what link we were using in this example:
https://myinstance.service-now.com/nav_to.do?uri=incident.do?sys_id=46e482d9a9fe198101d3e3f3e2a14459
In this next log statement, we analyze the destination URL to see if there is deep linking. The request URI is the page that is being accessed, and the “Query String” statement is the parameters on that URL.
Based on the URI an Query String, the script will attempt to use Deep Linking since it found query string parameters.
1 2 3 4 5 6 7 | requestURI: /nav_to.do Query String (qs): uri=incident.do?sys_id=46e482d9a9fe198101d3e3f3e2a14459 URI Parameter: incident.do?sys_id=46e482d9a9fe198101d3e3f3e2a14459 There may be Deep Linking involved with this SAML request |
If we were not deep linking, then most of those statements above would be empty, or show a “null” value.
Next SAML will try to generate a Relay State parameter. This is sent to the IdP. Once authentication is complete on the Identity Provider’s side, it will redirect back to ServiceNow and it will post this Relay State with the SAML Response. This lets ServiceNow know where to redirect the browser once the login is completed.
The SAML plugin will URL encode the Relay State value since this is going on the URL that we send to the IdP. We don’t want any special URL characters to interfere with the base URL redirection that we are doing.
If there is no relay state, then a default relay state is generated. Out of the box, this relay state will be the main page of your instance.
1 | Generating a Relay State of: https://myinstance.service-now.com/nav_to.do?uri=incident.do%3fsys_id%3d46e482d9a9fe198101d3e3f3e2a14459 |
Once the Relay State is generated, the system will generate an AuthnRequest XML document. This document will then be DEFLATED, base64 encoded, and URL Encoded and added to the URL as a “SAMLRequest” parameter. The log will show both the XML document for the request, and the full URL with SAMLRequest and RelayState that we will use for redirection to the IdP.
1 2 3 | <saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="https://myinstance.service-now.com/navpage.do" ForceAuthn="false" ID="SNC04bc590a4d03b653d77fb07a88a345eb" IsPassive="false" IssueInstant="2012-05-09T15:21:52.974Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ProviderName="https://myinstance.service-now.com/navpage.do" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://myinstance.service-now.com</saml2:Issuer><saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" SPNameQualifier="https://myinstance.service-now.com/navpage.do"/><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> Redirecting to: https://idp.ssocircle.com:443/sso/SSORedirect/metaAlias/ssocircle?SAMLRequest=nVPBcpswEP0VRneDwKa2NcYzlEynnklTYtwechPSYmsGJKoVjvP3BeIkPjTuJNfdp9333j6tkDd11LK0cwe9hT8doPNOTa2RPXcS0lnNDEeFTPMGkDnBivTHLYt8ylprnBGmJl6KCNYpozOjsWvAFmCPSsCv7W1CDs61LAi4LY0uzZN%2FMA1Ijb6xexYuKI0CzY8t34MvDfG%2BGStgJJSQitcIxNvcJKS4y%2BisFPGS8pmk0%2FJLPJXzeVXSOV8s%2BHQWQ9kDMeeI6ghvTxE72Gh0XLuERDSMJjSe0OUujFkUsjjyl%2FPZA%2FHys5SvSkul99d1l88gZN93u3yS%2Fyx244CjkmDvevRHJf8Gi713PT%2BfkvVqtJ6NzO3lNa6T4i8nIOv%2Fbl8FlzvOG1s2cN%2Fc5KZW4slL69o8Zha46%2FU428F4moa792mEfjhWlJxUI5RBw1WdSmkBkXhFPmy473itKgX2gzYFrzzPSQU5xqSPnIOT8zLTtNwqHIyEExfu1cpLWFb3Rm2h%2BpSxV2GCiWF2Xx5C%2BGisHEIFoue5s1xja6x7Mf5fjNbn5jv63tqXv3X9Fw%3D%3D&RelayState=https://myinstance.service-now.com/nav_to.do?uri=incident.do%3fsys_id%3d46e482d9a9fe198101d3e3f3e2a14459 |
Here, the user’s browser is redirected to the IdP for authentication. Logging is now the responsibility of the IdP. We will not receive any more log messages in the SAML process until the IdP processed the authentication and redirects the user back to ServiceNow with the SAML response document and relay state.
Logging resumes as we get the response back from the IdP. Before we act on the response, we first do a number of validation and security checks to ensure we can trust this SAML response.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | Response object created Issue Instant: 2012-05-09T15:22:01.000Z Signature Reference ID: s2e460726688ab83e1875101549b1ad03d4af8837a certificate Issuer DN: CN=CA, O=SSOCircle, C=DE Public key created Signature not in response, attempting to get signature from assertion Got signature <?xml version="1.0" encoding="UTF-8"?><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/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI="#s255bdf815a7493479752d610386841f58ac677211"> <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/2000/09/xmldsig#sha1"/> <ds:DigestValue>gtpu2XT1bLHTMkpQeTpiunMO1Yo=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> mCvayhe1KJaLy/o1D9kIpL1t99rTRdedpLw7KQIy9T/siDytBOgo42yr91sfcG2dc7AX/JuQpQh8 HGL63H0ZgadVEp0DlErc8jetkje3o6DgKd/Cw0HAMuJujhh83cFthkQDgX8xg9L7LUqgptqHds/5 ssLyVvCok3dJYyImPX8= </ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate> MIICjDCCAXSgAwIBAgIFAJRvxcMwDQYJKoZIhvcNAQEEBQAwLjELMAkGA1UEBhMCREUxEjAQBgNV BAoTCVNTT0NpcmNsZTELMAkGA1UEAxMCQ0EwHhcNMTEwNTE3MTk1NzIxWhcNMTYwODE3MTk1NzIx WjBLMQswCQYDVQQGEwJERTESMBAGA1UEChMJU1NPQ2lyY2xlMQwwCgYDVQQLEwNpZHAxGjAYBgNV BAMTEWlkcC5zc29jaXJjbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbzDRkudC/ aC2gMqRVVaLdPJJEwpFB4o71fR5bnNd2ocnnNzJ/W9CoCargzKx+EJ4Nm3vWmX/IZRCFvrvy9C78 fP1cmt6Sa091K9luaMAyWn7oC8h/YBXH7rB42tdvWLY4Kl9VJy6UCclvasyrfKx+SR4KU6zCsM62 2Kvp5wW67QIDAQABoxgwFjAUBglghkgBhvhCAQEBAf8EBAMCBHAwDQYJKoZIhvcNAQEEBQADggEB AJ0heua7mFO3QszdGu1NblGaTDXtf6Txte0zpYIt+8YUcza2SaZXXvCLb9DvGxW1TJWaZpPGpHz5 tLXJbdYQn7xTAnL4yQOKN6uNqUA/aTVgyyUJkWZt2giwEsWUvG0UBMSPS1tp2pV2c6/olIcbdYU6 ZecUz6N24sSS7itEBC6nwCVBoHOL8u6MsfxMLDzJIPBI68UZjz3IMKTDUDv6U9DtYmXLc8iMVZBn cYJn9NgNi3ghl9fYPpHcc6QbXeDUjhdzXXUqG+hB6FabGqdTdkIZwoi4gNpyr3kacKRVWJssDgak eL2MoDNqJyQ0fXC6Ze3f79CKy/WjeU5FLwDZR0Q= </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> Signature is valid. |
After the SAML response is validated and trusted by the system, we will process it and attempt to login using the nameId token passed back to use from the IdP.
The log will display the NameID token received from the IdP. We will match this up with a real user in our system and establish a valid ServiceNow session.
1 2 3 4 5 | NameID:john.user@service-now.com SAML2 NameID: john.user@service-now.com SAML2 SessionIndex: s2edd20d41d9a7f3fcdb02360877e9d8cfa313ac11 |
At this point, we redirect the user’s browser to the page indicated by the RelayState that was passed back to us from the IdP. This should be the same relay state that we sent to the IdP to hold on for us.
1 | We will be redirecting user to the RelayState: https://myinstance.service-now.com/nav_to.do?uri=incident.do?sys_id=46e482d9a9fe198101d3e3f3e2a14459 |
The user is then authenticated and redirected to the relay state’s URL.
John,
This is a fantastic article.
Hi John, great article!
I have an issue here in my company, where the security team don`t want to expose the idP page. Is there a way to make serviceNow call the idP page internally, instead of doing the redirect ?
Something like, serviceNow redirect it to itself (maybe a public UI Page), where we would do a internal call to idP and redirect back to the first page?
Thanks!
Marcelo…not that I know of. That goes against the premise of the POST Browser Redirect method of the SAML 2.0 protocol.