{"revision":"c10276e953456835cdbb1f3a60d58ae1980be353","document":{"id":40423,"path":"platform-security/authentication/c_Implementation.md","title":"Implement a nonce","bundle":null,"doc_type":null,"release":"australia","body":"\n# Implement a nonce\n\nAdd a cryptographic nonce to the authentication header for custom digest-based Single Sign- On \\(SSO\\) to confirm that each authentication token is valid for one use only. This implementation requires ServiceNow developer expertise.\n\nImplement a NONCE when your organization uses digest-based on Single Sign-On \\(SSO\\) authentication and requires that each authentication token can be used only once. This implementation requires developer expertise in ServiceNow scripting and knowledge of digest authentication protocols.\n\n**Note:** This topic is intended for developers and SSO administrators implementing custom authentication. For standard login configuration, see [Specify a login landing page](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/platform-security/authentication/t_SpecifyingALoginLandingPage.md).\n\n-   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.\n-   Create a new table called `u_authentication_nonce`. Add a field to the table called `u_nonce`.\n-   Go to **System Properties** &gt; **Installation Exits** and create an item called `DigestSingleSignOnNonce` which overrides ExternalAuthentication \\(**glide.authenticate.external\\_property**\\).\n-   Add the following code to the script portion of the newly created DigestSingleSignOnNonce.\n\n    ```\n    \n    gs.include(\"PrototypeServer\");\n    \n    var DigestSingleSignOnNonce = Class.create();\n    DigestSingleSignOnNonce.prototype = {\n    \t\n    \tprocess : function() {\n    \t\t\n    \t\tvar headerKey = GlideProperties.get(\"glide.authenticate.header.key\", \"SM_USER\");\n    \t\tvar headerDigestKey = GlideProperties.get(\"glide.authenticate.header.encrypted_key\", \"DIGEST\");\n    \t\tvar headerNonceKey = GlideProperties.get(\"glide.authenticate.header.nonce_key\", \"NCE\");\n    \t\tvar fieldName = GlideProperties.get(\"glide.authenticate.header.value\", \"user_name\");\n    \t\tvar fkey = GlideProperties.get(\"glide.authenticate.secret_key\");\n    \t\t\n    \t\t// Look in the Headers\n    \t\tvar data = request.getHeader(headerKey);\n    \t\tvar encdata = request.getHeader(headerDigestKey);\n    \t\tvar nonce = request.getHeader(headerNonceKey);\n    \t\t\n    \t\t// If not, then check the URL Parameters\n    \t\tif (data == null || encdata == null || nonce == null) {\n    \t\t\tdata = request.getParameter(headerKey);\n    \t\t\tencdata = request.getParameter(headerDigestKey);\n    \t\t\tnonce = request.getParameter(headerNonceKey);\n    \t\t}\n    \t\t\n    \t\t// then maybe its a cookie\n    \t\tif (data == null || encdata == null || nonce == null) {\n    \t\t\tvar cookies = request.getCookies();\n    \t\t\tdata = GlideCookieMan.getCookieValue(cookies, headerKey);\n    \t\t\tencdata = GlideCookieMan.getCookieValue(cookies, headerDigestKey);\n    \t\t\tnonce = GlideCookieMan.getCookieValue(cookies, headerNonceKey);\n    \t\t}\n    \t\t\n    \t\t// if found run encryption\n    \t\tif (data != null && encdata != null && nonce != null) {\n    \t\t\ttry {\n    \t\t\t\t\n    \t\t\t\t// Replace all spaces with plus(+)'s, converted in url\n    \t\t\t\tencdata = encdata.replaceAll(' ', '+');\n    \t\t\t\t\n    \t\t\t\t// ----- Encrypt the username|nonce\n    \t\t\t\tvar key = this.getDigest( data + \"|\" + nonce, fkey);\n    \t\t\t\t\n    \t\t\t\t// Check for match of received encoded data\n    \t\t\t\t// and your encoding of user name\n    \t\t\t\tif (encdata == key) {\n    \t\t\t\t\tvar ugr = new GlideRecord(\"sys_user\");\n    \t\t\t\t\tugr.initialize();\n    \t\t\t\t\tif (!ugr.isValidField(fieldName)) {\n    \t\t\t\t\t\tGlideLog.warn(\"External authorization is set to use field: '\"+ fieldName + \"' which doesn't exist\");\n    \t\t\t\t\t\treturn \"failed_missing_requirement\";\n    \t\t\t\t\t}\n    \t\t\t\t\tugr.addQuery(fieldName, data);\n    \t\t\t\t\tugr.query();\n    \t\t\t\t\tif (!ugr.next()) {\n    \t\t\t\t\t\tvar userLoad = GlideUser.getUser(data);\n    \t\t\t\t\t\tif (userLoad == null)\n    \t\t\t\t\t\t\treturn \"failed_authentication\";\n    \t\t\t\t\t\t\n    \t\t\t\t\t\tugr.initialize();\n    \t\t\t\t\t\tugr.addQuery(fieldName, data);\n    \t\t\t\t\t\tugr.query();\n    \t\t\t\t\t\tif (!ugr.next())\n    \t\t\t\t\t\t\treturn \"failed_authentication\";\n    \t\t\t\t\t\t\n    \t\t\t\t\t}\n    \t\t\t\t\t\n    \t\t\t\t\tif (this.processNonce(nonce)){\n    \t\t\t\t\t\tvar userName = ugr.getValue(\"user_name\");\n    \t\t\t\t\t\treturn userName;\n    \t\t\t\t\t}\n    \t\t\t\t\telse return \"failed_missing_requirement\";\n    \t\t\t\t\t}\n    \t\t\t\telse {\n    \t\t\t\t\t\n    \t\t\t\t\treturn \"failed_authentication\";\n    \t\t\t\t}\n    \t\t\t} catch(e) {\n    \t\t\t\tgs.log(e);\n    \t\t\t\treturn \"failed_authentication\";\n    \t\t\t}\n    \t\t\t// Encoded data didn't match recieved Encoded data\n    \t\t} else {\n    \t\t\t\n    \t\t\treturn \"failed_missing_requirement\";\n    \t\t}\n    \t},\n    \t\n    \tgetDigest : function( data, fkey ) {\n    \t\ttry {\n    \t\t\t// default to something JDK 1.4 has\n    \t\t\tvar MAC_ALG = \"HmacSHA1\";\n    \t\t\treturn SncAuthentication.encode(data, fkey, MAC_ALG);\n    \t\t\t\n    \t\t} catch (e) {\n    \t\t\tgs.log(e.toString());\n    \t\t\tthrow 'failed_missing_requirement';\n    \t\t}\n    \t} ,\n    \t\n    \tprocessNonce : function( sentNonce ) {\n    \t\tvar ngr = new GlideRecord(\"u_authentication_nonce\");\n    \t\t\n    \t\tngr.addQuery(\"u_nonce\", sentNonce);\n    \t\tngr.query();\n    \t\tif (ngr.next()) {\n    \t\t\tgs.log(\"This SSO entry has already been processed! (Nonce: \" + sentNonce + \")\");\n    \t\t\treturn false;\n    \t\t}\n    \t\tvar ngrNew = new GlideRecord(\"u_authentication_nonce\");\n    \t\tngrNew.initialize();\n    \t\tngrNew.u_nonce = sentNonce;\n    \t\tngrNew.insert();\n    \t\tgs.log(\"Inserted new nonce: \" + sentNonce);\n    \t\treturn true;\n    \t}\n    };      \n         \n    ```\n\n-   Once you've saved your new installation exit, go to the DigestSingleSignOn installation exit and make sure that it is set Active=false.\n\nYour instance should now be configured to implement a nonce.\n\n"}}