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 assists you in implementing a cryptographic nonce in the authentication header, ensuring that each nonce can only be used once to enhance security in your ServiceNow environment.
Show less
Key Features
- Create a system property named glide.authenticate.header.noncekey to specify the nonce variable name (e.g., NONCE or NCE).
- Introduce a new table, uauthenticationnonce, with a field unonce to store nonce values.
- Set up an installation exit called DigestSingleSignOnNonce that overrides ExternalAuthentication.
- Use provided JavaScript code to process authentication, including nonce validation and encryption checks.
Key Outcomes
After following these steps, you will have a nonce implementation that prevents replay attacks, ensures secure authentication, and logs the usage of each nonce. Ensure that the installation exit DigestSingleSignOn is set to Active=false to complete the configuration process.
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.