{"revision":"c10276e953456835cdbb1f3a60d58ae1980be353","document":{"id":42502,"path":"platform-user-interface/service-portal/enable-esignature-sp.md","title":"Enable e-signature for Service Portal","bundle":null,"doc_type":null,"release":"australia","body":"\n# Enable e-signature for Service Portal\n\nYou can configure e-signature in Service Portal to require re-authentication from approving users.\n\n## Before you begin\n\nThe **com.snc.integration.esig.window** system property is supported to enable SSO login in a new window.\n\nRole required: admin\n\n## Procedure\n\n1.  Activate the Approvals with e-Signature \\[com.glide.e\\_signature\\_approvals\\] plugin.\n\n2.  Navigate to **System Definition** &gt; **e-Signature Registry**.\n\n3.  Add any tables you want to require an e-signature for to the list.\n\n\n## Result\n\nWith e-signature enabled, approvers are required to provide a password to approve or reject any requests. Authentication with touch ID works in the mobile app. On the mobile web, approvers are still required to enter a password. For more information on configuring e-signature, see .\n\n**Parent Topic:**[Managing portal access](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/platform-user-interface/service-portal/portal-security.md)\n\n## Enable SSO login in a new window\n\nOpen a new window for SSO authentication when using e-Signature for approvals.\n\n### Before you begin\n\nSecurity Assertion Markup Language \\(SAML\\) login is only supported on the desktop Service Portal.\n\nFor additional information, see the [e-signature SSO login KB article](https://support.servicenow.com/kb?id=kb_article_view&sys_kb_id=2dca1fe8db49a010190b1ea668961999).\n\nRole required: admin\n\n### Procedure\n\n1.  Enter the spEsignatureCustom script.\n\n    1.  Enter `sys_ui_script.list` in the Filter navigator.\n\n    2.  Select **New**, and create a new UI script.\n\n    3.  On the UI Script form, enter `spEsignatureCustom` in the API Name field.\n\n    4.  In the UI Type field, select **Mobile/Service Portal**.\n\n    5.  Paste the [spEsignatureCustom script](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/platform-user-interface/service-portal/enable-esignature-sp.md) in the **Script** field.\n\n    6.  Select **Submit**.\n\n2.  Enter the spAuthCustom script.\n\n    1.  In the same `sys_ui_script.list` table, create another new UI script by selecting **New**.\n\n    2.  On the UI Script form, enter `spAuthCustom` in the API Name field.\n\n    3.  In the UI Type field, select **Mobile/Service Portal**.\n\n    4.  Paste the [spAuthCustom script](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/platform-user-interface/service-portal/enable-esignature-sp.md) in the **Script** field.\n\n    5.  Select **Submit**.\n\n3.  Associate the UI scripts to the JS Include record.\n\n    1.  Navigate to **Service Portal** &gt; **Portals**.\n\n    2.  Identify the Service Portal you want to apply the esignature support to and select the Theme.\n\n    3.  In the related lists, select **JS Includes**.\n\n    4.  Select **New**.\n\n    5.  On the form, fill in the fields.\n\n        |Field|Description|\n        |-----|-----------|\n        |Display name|Name for your JS Include. Enter `spEsignatureCustom` and associate the record with the spEsignatureCustom UI script you created, or enter `spAuthCustom` and associate the record with spAuthCustom you created.|\n        |Source|Source for your JS Include record. Select **UI Script**.|\n        |UI script|UI script source for your JS Include record. Select either spEsignatureCustom or spAuthCustom depending on the record you're creating.|\n        |Application|Application for your JS Include record. The default application is **Global**.|\n        |Updated|Field displaying when the record was last updated.|\n        |Package|Field that establishes the JS Include package.|\n\n    6.  Select **Submit**.\n\n\n### Result\n\nA new window opens when you use E-Signature for approvals.\n\n## spEsignatureCustom script\n\nPaste the spEsignatureCustom script in the sys\\_ui\\_script.list script field.\n\n```\nangular.module('sn.$sp').provider('spEsignature', function() {\n\t'use strict';\n\n\tthis.$get = function spEsignature($q, $http, $window, urlTools, xmlUtil) {\n\t\tvar w = window;\n\t\tvar esignOW;\n\t\tvar windowWidth;\n\t\tvar windowHeight;\n\t\tvar redirectURL;\n\n\t\tfunction isWindowChosen() {\n\t\t\tvar postParams = {\n\t\t\t\tsysparm_scope: 'global',\n\t\t\t\tsysparm_processor: 'ESignatureAuthUtils',\n\t\t\t\tsysparm_name: 'isWindowChosen'\n\t\t\t};\n\t\t\treturn $http({\n\t\t\t\tmethod: 'POST',\n\t\t\t\turl: '/xmlhttp.do',\n\t\t\t\tdata: urlTools.encodeURIParameters(postParams),\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded'\n\t\t\t\t},\n\t\t\t\ttransformResponse: function(response) {\n\t\t\t\t\treturn xmlUtil.getDataFromXml(response);\n\t\t\t\t}\n\t\t\t}).then(\n\t\t\t\tfunction(response) {\n\t\t\t\t\tvar data = response.data ? response.data[0] : {};\n\t\t\t\t\treturn data.answer ===  'true'\n\t\t\t\t},\n\t\t\t\tfunction(response) {\n\t\t\t\t\t// Handling failure case.\n\t\t\t\t\tswitch (response.status) {\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\tcase 404:\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tfunction initiateEsignature() {\n\t\t\tvar postParams = {\n\t\t\t\tsysparm_scope: 'global',\n\t\t\t\tsysparm_processor: 'ESignatureAuthUtils',\n\t\t\t\tsysparm_name: 'fetchAuthDetails'\n\t\t\t}\n\t\t\treturn $http({\n\t\t\t\tmethod: 'POST',\n\t\t\t\turl: '/xmlhttp.do',\n\t\t\t\tdata: urlTools.encodeURIParameters(postParams),\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded'\n\t\t\t\t},\n\t\t\t\ttransformResponse: function(response) {\n\t\t\t\t\treturn xmlUtil.getDataFromXml(response, 'result');\n\t\t\t\t}\n\t\t\t}).then(\n\t\t\t\tfunction(response) {\n\t\t\t\t\tvar data = response.data ? response.data[0] : {};\n\t\t\t\t\tprocess(data);\n\t\t\t\t});\n\t\t}\n\n\t\tfunction process(data) {\n\t\t\tvar shouldLogoutFirst = data.logoutFirst === 'true';\n\t\t\tw['windowHeight'] = data.popup_window_height;\n\t\t\tw['windowWidth'] = data.popup_window_width;\n\t\t\tw['redirectURL'] = data.loginURL;\n\t\t\tif (shouldLogoutFirst)\n\t\t\t\topenEsignatureWindow(data.logoutURL);\n\t\t\telse\n\t\t\t\tauthenticate();\n\t\t}\n\n\t\tfunction openEsignatureWindow(url) {\n\t\t\tw['esignOW'] = window.open(url, 'esignatureAuthentication',\n\t\t\t\t'height='+w['windowHeight']+',width='+w['windowWidth']+',top=100,left=100,toolbar=0,location=0,menubar=0');\n\t\t}\n\n\t\tw['authenticate'] = function(){\n\t\t\tif(w['redirectURL']){\n\t\t\t\tif(w['esignOW']) //when we signed out previously, a window is already opened. reuse it.\n\t\t\t\t\tw['esignOW'].location.href = w['redirectURL'];\n\t\t\t\telse\n\t\t\t\t\topenEsignatureWindow(w['redirectURL']);\n\t\t\t}\n\t\t};\n\n\t\tw['evaluateRedirect'] = function(msg) {\n\t\t\tw['esignOW'].close();\n\t\t\tif (msg == \"saml2 login complete\") {\n\t\t\t\t$window.onReauthenticationComplete(msg);\n\t\t\t}\n\t\t};\n\n\t\treturn {\n\t\t\tisWindowChosen: isWindowChosen,\n\t\t\tinitiateEsignature: initiateEsignature\n\t\t};\n\n\t};\n});\n\n```\n\n## spAuthCustom script\n\nPaste the spAuthCustom script in the sys\\_ui\\_script.list script field.\n\n```\nangular.module('sn.$sp').factory('spAuthModal', function($q, spModal, i18n, $http, spAuthentication, glideUserSession, cabrillo, $cookies, $window, spUtil, $uibModal, spEsignature) {\n\t\"use strict\";\n\n\tfunction _showAuthenticationModal(requestParams, username, userSysId) {\n\t\tvar currentUser;\n\t\tvar deferred = $q.defer();\n\t\tglideUserSession.loadCurrentUser({reload: true}).then(function(user) {\n\t\t\tif (!user) {\n\t\t\t\tdeferred.reject({\n\t\t\t\t\terror: {\n\t\t\t\t\t\tstatus: 'ANONYMOUS',\n\t\t\t\t\t\tmessage: i18n.getMessage('Not logged in')\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcurrentUser = user;\n\t\t\tvar serializedUser = {\n\t\t\t\tsysId: currentUser.userID,\n\t\t\t\tuserName: currentUser.userName,\n\t\t\t\tfirstName: currentUser.firstName,\n\t\t\t\tlastName: currentUser.lastName\n\t\t\t};\n\n\t\t\t// hand off to native clients\n\t\t\tif (cabrillo.isNative()) {\n\t\t\t\tcabrillo.auth.reauthenticate(currentUser).then(function() {\n\t\t\t\t\tdeferred.resolve(serializedUser);\n\t\t\t\t}, function(error) {\n\t\t\t\t\tif (error && error.status) {\n\t\t\t\t\t\tdeferred.reject({\n\t\t\t\t\t\t\terror: error\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\t//TODO: Handle rejection a little more gracefully\n\t\t\t\t\tdeferred.reject();\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar loginMethod = currentUser.$private.loginMethod;\n\t\t\tif (!loginMethod) {\n\t\t\t\t// As we were unable to determine the login method via the HTTP session, trying to get glide_sso_id cookie which is set in case of multisso login\n\t\t\t\tvar providerSysId = $cookies.get('glide_sso_id');\n\t\t\t\tloginMethod = providerSysId ? 'multisso' : 'db';\n\t\t\t}\n\n\t\t\tif (loginMethod === 'saml' || loginMethod === 'oidc' || loginMethod === 'multisso') {\n\t\t\t\tspEsignature.isWindowChosen().then(function(result) {\n\t\t\t\t\tvar modal;\n\t\t\t\t\tif (!spUtil.isMobile() && loginMethod !== 'oidc' && result === true) {\n\t\t\t\t\t\t// If enabled, Opening a new window for desktop saml login\n\t\t\t\t\t\tspEsignature.initiateEsignature();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tglideUserSession.getSsoReauthenticationUrl().then(function(url) {\n\t\t\t\t\t\t\trequestParams.externalLoginURL = url;\n\t\t\t\t\t\t\topenExternalAuthModal(requestParams).then(function(m) {\n\t\t\t\t\t\t\t\tmodal = m;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\t$window.onReauthenticationComplete = function(result) {\n\t\t\t\t\t\tdeferred.resolve(serializedUser);\n\t\t\t\t\t\tif (modal)\n\t\t\t\t\t\t\tmodal.close();\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tspModal.open({\n\t\t\t\t\ttitle:i18n.getMessage(\"Approver authentication\"),\n\t\t\t\t\tmessage:i18n.getMessage(\"Additional authentication is required, enter your usename and password to continue.\"),\n\t\t\t\t\tfooterStyle: {border: 'none', 'padding-top': 0},\n\t\t\t\t\twidget: 'simpleloginui',\n\t\t\t\t\twidgetInput: {},\n\t\t\t\t\tshared: requestParams,\n\t\t\t\t\tonSubmit: function() {\n\t\t\t\t\t\treturn onLoginModalSubmit(requestParams, username);\n\t\t\t\t\t}\n\t\t\t\t}).then(function(confirm) {\n\t\t\t\t\tif (confirm.label == i18n.getMessage(\"OK\")) {\n\t\t\t\t\t\tdeferred.resolve(serializedUser);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdeferred.reject();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\treturn deferred.promise;\n\t}\n\n\tfunction onLoginModalSubmit(requestParams, username) {\n\t\t//(1) call login service to verify auth\n\t\t//(2) verify same user\n\t\treturn $q(function(resolve, reject) {\n\t\t\tvar errorMessage = null;\n\n\t\t\tif(!requestParams.username || requestParams.username.trim() === \"\" ||\n\t\t\t\t\t!requestParams.password || requestParams.password.trim() === \"\") {\n\t\t\t\terrorMessage = i18n.getMessage(\"User name or password invalid\");\n\t\t\t} else if(requestParams.username !== username) {\n\t\t\t\terrorMessage = i18n.getMessage(\"Attempted to authenticate as a different user\");\n\t\t\t}\n\n\t\t\tif(!errorMessage || errorMessage === \"\") {\n\t\t\t\tspAuthentication.validateCreds(requestParams.username, requestParams.password).then(function(res) {\n\t\t\t\t\tresolve({status: res.success, errorMessage: res.message});\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tresolve({status: !errorMessage || errorMessage === \"\", errorMessage: errorMessage});\n\t\t\t}\n\t\t});\n\n\t}\n\n\tfunction openExternalAuthModal(requestParams) {\n\t\tvar deferred = $q.defer();\n\n\t\tvar options = {\n\t\t\ttitle: i18n.getMessage(\"Approver authentication\"),\n\t\t\tmessage: '',\n\t\t\tmessageOnly: false,\n\t\t\terrorMessage: '',\n\t\t\tinput: false,\n\t\t\tlabel: '',\n\t\t\tsize: 'lg',\n\t\t\tvalue: '',\n\t\t\trequired: false,\n\t\t\tfooterStyle: {border: 'none', 'padding-top': 0},\n\t\t\tvalues: false,\n\t\t\tonSubmit: null,\n\t\t\twidget: 'simpleloginui',\n\t\t\twidgetInput: {},\n\t\t\tshared: requestParams,\n\t\t\tbuttons: [{label: i18n.getMessage('Cancel'), cancel:true}]\n\t\t};\n\n\t\tvar widgetURL = spUtil.getWidgetURL(options.widget);\n\t\t$http.post(widgetURL, options.widgetInput).success(function(response) {\n\t\t\toptions.widget = response.result;\n\t\t\toptions.widget.options.shared = options.shared;\n\t\t\tvar modal = $uibModal.open({\n\t\t\t\ttemplateUrl:'sp-modal.html',\n\t\t\t\tcontroller: spModalCtrl,\n\t\t\t\tsize: options.size,\n\t\t\t\tresolve: {\n\t\t\t\t\toptions: function() {\n\t\t\t\t\t\treturn options;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tdeferred.resolve(modal);\n\t\t});\n\t\t\n\t\treturn deferred.promise;\n\t}\n\n\tfunction spModalCtrl($scope, options) {\n\t\t$scope.options = options;\n\t\t$scope.form = {};\n\n\t\t$scope.buttonClicked = function(button){\n\t\t\tif (button.cancel) {\n\t\t\t\t$scope.$dismiss();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tprompt: _showAuthenticationModal\n\t}\n}).decorator(\"spAuthModal\", function($delegate) { return( $delegate );});\n\n```\n\n"}}