Implement a nonce
Summarize
Summarized using AI
This content was generated using new OpenAI-powered functionality. Results are provided on an as is basis and are not guaranteed to be accurate or complete.
Summary of Implement a nonce
This guide provides instructions to implement a cryptographic nonce in the authentication header for a ServiceNow instance, enhancing security by ensuring that each nonce can only be used once. This process involves creating a system property, a new table, and a custom script.
Show less
Key Features
- System Property: Create a property named
glide.authenticate.header.noncekeyto define the variable for the nonce. - Database Table: Establish a custom table called
uauthenticationnoncewith a fieldunonceto store nonce values. - Script Creation: Implement a script in the
DigestSingleSignOnNonceitem to handle nonce processing and validation during authentication.
Key Outcomes
After following these steps, your ServiceNow instance will effectively manage nonce values during authentication, preventing replay attacks and improving overall security. Ensure that the DigestSingleSignOn installation exit is set to Active=false to finalize the configuration.
Add a cryptographic nonce to the authentication header to ensure that it can only be used once.
- Create a system property called glide.authenticate.header.nonce_key and set its value to whatever variable name you're using for the nonce, such as NONCE or NCE.
- Create a new table called
u_authentication_nonce. Add a field to the table calledu_nonce. - Go to and create an item called DigestSingleSignOnNonce which overrides ExternalAuthentication (glide.authenticate.external_property).
- Add the following code to the script portion of the newly created DigestSingleSignOnNonce.
gs.include("PrototypeServer"); var DigestSingleSignOnNonce = Class.create(); DigestSingleSignOnNonce.prototype = { process : function() { var headerKey = GlideProperties.get("glide.authenticate.header.key", "SM_USER"); var headerDigestKey = GlideProperties.get("glide.authenticate.header.encrypted_key", "DIGEST"); var headerNonceKey = GlideProperties.get("glide.authenticate.header.nonce_key", "NCE"); var fieldName = GlideProperties.get("glide.authenticate.header.value", "user_name"); var fkey = GlideProperties.get("glide.authenticate.secret_key"); // Look in the Headers var data = request.getHeader(headerKey); var encdata = request.getHeader(headerDigestKey); var nonce = request.getHeader(headerNonceKey); // If not, then check the URL Parameters if (data == null || encdata == null || nonce == null) { data = request.getParameter(headerKey); encdata = request.getParameter(headerDigestKey); nonce = request.getParameter(headerNonceKey); } // then maybe its a cookie if (data == null || encdata == null || nonce == null) { var cookies = request.getCookies(); data = GlideCookieMan.getCookieValue(cookies, headerKey); encdata = GlideCookieMan.getCookieValue(cookies, headerDigestKey); nonce = GlideCookieMan.getCookieValue(cookies, headerNonceKey); } // if found run encryption if (data != null && encdata != null && nonce != null) { try { // Replace all spaces with plus(+)'s, converted in url encdata = encdata.replaceAll(' ', '+'); // ----- Encrypt the username|nonce var key = this.getDigest( data + "|" + nonce, fkey); // Check for match of received encoded data // and your encoding of user name if (encdata == key) { var ugr = new GlideRecord("sys_user"); ugr.initialize(); if (!ugr.isValidField(fieldName)) { GlideLog.warn("External authorization is set to use field: '"+ fieldName + "' which doesn't exist"); return "failed_missing_requirement"; } ugr.addQuery(fieldName, data); ugr.query(); if (!ugr.next()) { var userLoad = GlideUser.getUser(data); if (userLoad == null) return "failed_authentication"; ugr.initialize(); ugr.addQuery(fieldName, data); ugr.query(); if (!ugr.next()) return "failed_authentication"; } if (this.processNonce(nonce)){ var userName = ugr.getValue("user_name"); return userName; } else return "failed_missing_requirement"; } else { return "failed_authentication"; } } catch(e) { gs.log(e); return "failed_authentication"; } // Encoded data didn't match recieved Encoded data } else { return "failed_missing_requirement"; } }, getDigest : function( data, fkey ) { try { // default to something JDK 1.4 has var MAC_ALG = "HmacSHA1"; return SncAuthentication.encode(data, fkey, MAC_ALG); } catch (e) { gs.log(e.toString()); throw 'failed_missing_requirement'; } } , processNonce : function( sentNonce ) { var ngr = new GlideRecord("u_authentication_nonce"); ngr.addQuery("u_nonce", sentNonce); ngr.query(); if (ngr.next()) { gs.log("This SSO entry has already been processed! (Nonce: " + sentNonce + ")"); return false; } var ngrNew = new GlideRecord("u_authentication_nonce"); ngrNew.initialize(); ngrNew.u_nonce = sentNonce; ngrNew.insert(); gs.log("Inserted new nonce: " + sentNonce); return true; } }; - Once you've saved your new installation exit, go to the DigestSingleSignOn installation exit and make sure that it is set Active=false.
Your instance should now be configured to implement a nonce.