Content Management features within ServiceNow are all the rave with customers. Everyone is interested with building out self service web pages that serve as a beautifully tailored front end to may of their ServiceNow applications. The downside, however, is that those companies using SAML 2.0 have to deal with their CMS rules competing with redirection rules within the SAML 2.0 setup.
One such customer wanted to implement SAML 2.0 along side of CMS. When the user finishes logging into ServiceNow through the SAML mechanisms, they wanted the system to determine that user’s role and redirect them to a specific CMS URL based upon that role, rather that using SAML’s default redirection to the home page.
I decided that this might be something others would like to implement in the future, so I developed a module to administer this along with a script include to provide libraries to facilitate the decisions for the home page redirection.
These changes are included in an update set. I didn’t want the update set modifying the SAML plugin automatically, however, so in combination with the update set, you will be asked to make modifications to the SAML login script manually. It is a simple change, however, and I intend to take you through the easy steps of making the modification.
The Update Set
The attached update set will do the following:
1) Add a “RoleBasedAuthHelper” script include that we will use in the SAML 2 Login Script
2) Creates a table called “Role Based Home Pages” and creates a module for it in the SAML application (See image below). You can specify specific URL’s for a given role. If a user has more than one of the roles in the list, it will obey the Order and use the one with the lower order.
3) Creates a system property to enable/disable debug logging for this feature. The system property is set to false (no debug logging) by default. The name of the property is: “com.snc.integration.saml2.role_based_auth_redir.verbose”.
Modifying the SAML 2 Login Script
Once you have uploaded the update set into your instance, you will want to modify the SAML 2 Login Script to use the role based home page redirection.
To do this, browse to the “Login Script” module of the “SAML 2 Single Sign-on” application. Then do the following:
Modify the “loginUser function”
It will look something like: “loginUser : function (nameId)”
Find these two lines in that function:
1 2 | var relayState = request.getParameter("RelayState"); if(relayState){ |
Add the following code block after the two lines listed above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // // Customized code added to redirect user to home page as decided by role // only if the relay state is indicating that there is no // deep linking // if (relayState == this.serviceURL) { var rbah = new RoleBasedAuthHelper(userName); var newRelayState = rbah.getRelayStateByRole(); if (newRelayState) { relayState = newRelayState; } } // // End of Customized Code Block // |
Process Flow
Let’s talk about what you can expect with this setup. First of all, if a user is coming into the instance by using a Deep Link (eg. clicking on the link to a incident from an email notification) we will not query the role of the user, but instead we will honor the intended destination of the link from the email message.
Second, if the user comes into ServiceNow with an active session, it will not trigger the SAML authentication and thus our logic will not be triggered. We are not modifying the default system navigation functionality.
If the user attempts to go to your ServiceNow instance and they don’t have an active session, the SAML authentication kicks in. Once the SAML authentication is complete and we are getting ready to log the user into the system, our custom code checks to see if SAML is telling us to go to the default home page. If it is, then we query our “Role Based Home Pages” table for any roles that may have default home page urls. The first one we find (according to the ordering rules set by the administrator) will be the url that we set in the SAML Relay State. This will override the request for us to redirect to the home page. The user will instead be redirected to the URL specified by the Role Based Home Page table.
Download the Update Set
WARNING: This update set is quite old and has not been tested with the newest versions of ServiceNow.
Update Set:
Role Based Home Pages with SAML 2.0
Hi John,
Can we not implement this using Login Rules?
Amit
@Amit. Not out of the box as SAML doesn’t honor Login Rules for CMS. It might be possible to somehow utilize the CMS module for Login Rules here, but the customer wanted this to be Role based which is not taken into account by default on the Login Rules. Finally, by breaking it out side of Login Rules, this then applies for anyone logging into the system, whether CMS is used or not.
John,
Thanks for putting the details along with updateset. I already implemented into our ServiceNow instance and it works great.
You are super!
Thanks
I have logged a PROBLEM ticket with our development team at ServiceNow. The goal is to have the Login Rules to support SAML authentication so that customers don’t have to use this customization.
John,
Do you know if this functionality is impacted with the SAML 2.0 Update 1?
Thanks
@Jeff, You will edit the same script, but the functions in that script will be a little different. I don’t anticipate huge differences, if any, in this code.
Hi John,
We currently redirect users to their particular unique homepage when they access ServiceNow. However, we have a request to redirect all users accessing ServiceNow through specific links on our intranet portal page to be redirected the Self-Service homepage, regardless of the users default homepage. Is this possible?
Thanks,
Marcia
Marcia, I believe you could accomplish this by having the unique home page generate links to servicenow with the deep-linking format (eg. nav_to.do). I believe this would override default homepage settings. Check out the wiki for this url format at: http://wiki.servicenow.com/index.php?title=Navigating_by_URL
Thanks John. We will try this!
Hi John,
I have used this solution to redirect users to specific homepages. As it is based on Role, how can I redirect the End users to ESS portal as end users will not have any role?
Regards
Swapna
Hi John,
Thanks for this post. It works great.
We have used this to redirect the users to specific homepages based on their role using saml authentication, but how to identify End users as they don’t have any role, how can i direct them to ESS portal using this solution. We cannot give any role to end users as it consumes a license.
Regards
Swapna
This is great stuff! thanks for that.
Swapna,
I have implemented this solution in a few clients. If you set the default login page in the SAML properties to http://yourinstance.service-now.com/ess/ then you can default users without roles to the main cms portal and then setup rules for users with roles to point to other pages.
Thanks for spending time on this. It works fine for the request we have here based on the number of ticketing systems are being replaced by Service-now.
Would it be possible for someone to post what the script looks like exactly for SAML2 Update 1?
Hi james,
I have created my custom login page in HTML5 on CMS SNOW .now i want to make it global for every user (who login to SNOW),he should must login throgh custom login page instead of SNOW default page.
For this i tried Login rules and Configuration page but not success. Please tell me is there any way to setup .
I’m trying to get what John Shatney recommended to Swapna working and am running into some issues (looping login, errors).
We want to make the ESS Portal the main landing page and use the Role Based Rules to route itil users to the normal out-of-the-box landing page.
Can anyone point me in the right direction please?
This worked a treat! Thank you so very much!
John,
We haven’t found much on the topic but how do you handle all the old links like the KB permlink etc so they are redirected to the CMS during the active session. Since Saml is not in play during this time we are worried about all the different URL in Website etc that point back to old URLs without the CMS.
Thanks in advance for any help
We just installed the SAML 2 plug in yesterday.
The login script reads:
gs.include(“PrototypeServer”);
var SAML2SingleSignon_update1 = Class.create();
SAML2SingleSignon_update1.prototype = {
initialize: function() {
this.serviceURL = gs.getProperty(“glide.authenticate.sso.saml2.service_url”);
this.userField = gs.getProperty(“glide.authenticate.sso.saml2.user_field”);
this.SAML2 = new SAML2_update1();
},
process: function() {
var Session = GlideUISession;
var relayState = request.getParameter(“RelayState”);
var samlResponseObject = this.SAML2.getSAMLObjectFromRequest(request);
// Refresh login request
if(!samlResponseObject && !relayState) {
var redirectURL = this.SAML2.generateAuthnRequestRedirectURL(request);
return redirectURL;
}
var inResponseTo = request.getSession().getAttribute(“glide.saml2.session_request_id”);
if (this.SAML2.isLogoutResponse(samlResponseObject)) {
if(!this.SAML2.validateLogoutResponseObject(samlResponseObject, inResponseTo)) {
this.logError(“Could not validate SAML LogoutResponse”);
gs.eventQueue(this.SAML2.logoutFailureEventId, null, Session.getId(request.getSession()), “SAML2 LogoutResponse validation failed.”);
}
return “logout_success”;
}
// If none of above, this is login response from IDP.
return this.loginProcess(samlResponseObject, inResponseTo);
},
loginProcess : function(samlResponseObject, inResponseTo) {
if (!this.SAML2.validateLoginResponse(samlResponseObject, inResponseTo)) {
this.logError(“Could not validate SAMLResponse”);
return “failed_authentication”;
}
var nameId = this.SAML2.getSubjectNameID();
if (nameId == null) {
this.logError(“Could not extract Subject NameID from SAMLResponse”);
return “failed_missing_requirement”;
}
this.logDebug(“SAML2 NameID: ” + nameId);
var sessionIndex = this.SAML2.getSessionIndex();
if (sessionIndex == null) {
this.logError(“Could not extract SessionIndex from SAMLResponse”);
return “failed_missing_requirement”;
}
this.logDebug(“SAML2 SessionIndex: ” + sessionIndex);
// pass these values to Logout script
request.getSession().setAttribute(“glide.saml2.session_index”, sessionIndex);
request.getSession().setAttribute(“glide.saml2.session_id”, nameId);
return this.loginUser(nameId);
},
loginUser : function (nameId) {
if (nameId == null) {
return “failed_missing_requirement”;
}
var ugr = new GlideRecord(“sys_user”);
ugr.addQuery(this.userField, nameId);
ugr.query();
if (!ugr.next()) {
var errorMessage = gs.getMessage(“User: “) + nameId + gs.getMessage(” not found”);
this.logDebug(errorMessage);
gs.addErrorMessage(errorMessage);
return “failed_authentication”;
}
var userName = ugr.getValue(“user_name”);
var relayState = request.getParameter(“RelayState”);
if(relayState){
this.logDebug(“We will be redirecting user to the RelayState: ” + relayState);
action.setRedirect(relayState);
}
return userName;
},
logDebug : function (msg) {
this.SAML2.logDebug(msg);
},
logError : function (msg) {
var lMsg = gs.getMessage(msg);
gs.log(lMsg);
gs.addErrorMessage(lMsg);
}
};
Can you update this post to show where the code block should be input in the script and if any other script changes are needed.
Thank you!
John,
Thank you for posting this mod, I implemented it without a hitch on the most current version of SNOW.
I noticed your post on March 26, 2013. I agree, this is functionality that needs to be incorporated into SNOW OOB.
Now the question: “Is there a version of this mod mod for the Multi-provider SSO plugin?”
Thank you,
Jim
Hey Jim, unfortunately, I don’t have an example of this with the new Multi-Provider SSO plugin.
The users in our instance meet one of the following criteria:
1. Have itil role, and possibly more.
2. Have a liaison role.
3. Have no role.
Users in case 1 or 2 will be taken to a certain page (a different one for each role), and users in case 3 should go to ess.
After adding the entries to the role based homepage, we have taken care of case 1 and 2.
For users that have no role, would adding: return ‘http://myinstance.service-now.com/ess/ ‘; to the getRelayStateByRole function, after the function has not found any custom home pages for the specified user/role, meet this requirement?
My tests so far seem to indicate this would meet our requirement (also sounds like what commenter David Webb had described above), provided we had accounted for roled users in our role based homepage table.
The getRelayStateByRole function in it’s modified state:
getRelayStateByRole: function(){
this.logDebug(“Attempting to see if any roles for the user have a custom home page we need to redirect to after login”);
var redir = new GlideRecord(“u_role_based_home_page”);
redir.orderBy(“u_order”);
redir.query();
while(redir.next()){
this.logDebug(“There is a home page for role: “+redir.u_role.name+”. Checking to see if it applies to “+this.user.user_name);
if(this._userHasRole(redir.u_role)){
this.logDebug(this.user.user_name+” has the “+redir.u_role.name+” role. Redirecting to “+redir.u_url);
return redir.u_url;
}
}
this.logDebug(“Could not find any custom home pages for “+this.user.user_name+”. Will default to existing relay state.”);
return ‘http://myinstance.service-now.com/ess/’;
}
Good one John! This helped us a lot. We further made minor changes on the script and table so that it behaves like a login rule (navigating based on condition set on users profile)
Hi John ,
Is there any way we can authenticate user from multiple table in the SSO Script and then redirect user to a particular page with the script given by you.
Here i want to authenticate user from our custom partner user table , i tried to modified the loginUser function to authenticate user from Partner User table too but once it authenticate and redirect to page specified in script it shows nothing just a blank page with URL myinstancename.service-now.com/navpage.do pop up.
Can you please suggest if SNOW allow to authenticate user from any other table apart from User Table.
John to the rescue yet again.
Many thanks for an elegant and simple solution to a complicated problem. You saved me hours of head-to-desk banging.
If you leave the roles field EMPTY will it apply it to all users who don’t have a role? If not, how do I get all non-rolled users to redirect to a CMS page?
Hi John,
Were you able to come up with something on this to work with the Multi Provider Single Sign On plugin.
Hi John,
Thanks a lot for this wonderful for article. is such kind of redirection also possible with Multi Provider Single Sign On ?
Regards, Bharat