Ayuda sobre productos BOLD:
Acceso SSO
ATENCIÓN: El siguiente contenido es de uso avanzado y su utilización puede ocasionar daños irreparables en la configuración del sistema
Single Sign On (SSO) es una técnica con la cual se evita a los usuarios que ya han estado autenticados en un primer sistema (han introducido login y password) la necesidad de volver a introducirlo en otros sistemas a los que acceden desde el primero.
Acceso a portal de BOLD por Single Sign On
El funcionamiento en líneas generales es el siguiente:
- El usuario ya se ha autenticado la página web del portal origen
- En esta página dispone de un enlace que le permite acceder al portal de BOLD
- Al hacer clic, acceder a la página interna del portal de BOLD sin necesidad de volver a introducir credenciales
Configuración técnica
Ejemplo HTML de conexión SSO
Desde el código javascript de la página web es necesario interceptar el clic sobre el enlace y preparar el mensaje HTTP POST con los datos adecuados para que al traspasar el control al portal de BOLD, éste ya no pregunte por la credenciales del usuario.
El funcionamiento es el siguiente:
1. Obtenemos los parámetros firmados. 2. Hacemos un POST a http://<URL_PORTAL>/faces/admin/indexSSO.xhtml 3. El Portal valida los parámetros firmados contra <GPSNodeURL> 4. Si la validación es satisfactorio se accede al Portal. 5. Si no se muestra un mensaje de error.
Código ejemplo y parámetros de la llamada
En el siguiente enlace se puede descargar un fichero HTML (TestSSO.html) con el código de ejemplo que deberá reimplementarse en el portal origen:
http://www.gps-plan.com/wiki/content/TestSSO.html (seleccionar botón derecho "Grabar como..." para obtener el código).
<head> <script type="text/javascript" src="jquery-3.2.1.min.js"></script> <script> function postToUrl(path, params, newWindow) { //Null check var method = "post"; // Set method to post by default var documentObject = document; if( newWindow ) { var win=window.open('about:blank'); if (!win) { alert(TRANS("Error: no se puede acceder a la pantalla (recuerde que debe permitir las ventanas emergentes en este sitio)")); return; } documentObject = win.document; } // The rest of this code assumes you are not using a library. // It can be made less wordy if you use one. var form = documentObject.createElement("form"); form.setAttribute("method", method); form.setAttribute("action", path); //Fill the hidden form if (typeof params === 'string') { var hiddenField = documentObject.createElement("input"); hiddenField.setAttribute("type", "hidden"); hiddenField.setAttribute("name", 'data'); hiddenField.setAttribute("value", params); form.appendChild(hiddenField); } else { for (var key in params) { if (params.hasOwnProperty(key)) { var hiddenField = documentObject.createElement("input"); hiddenField.setAttribute("type", "hidden"); hiddenField.setAttribute("name", key); if(typeof params[key] === 'object'){ hiddenField.setAttribute("value", JSON.stringify(params[key])); } else{ hiddenField.setAttribute("value", params[key]); } form.appendChild(hiddenField); } } } documentObject.body.appendChild(form); form.submit(); } function connectSSO() { gotoToPortal("TEST", "administrador", "user998871", "http://localhost/gpsnode/portal/ws/prepareSSO", // URL que genera los datos de autenticación firmados "http://localhost:8080/portal_DemoTiendas/faces/admin/indexSSO.xhtml" // URL base del portal ); /* gotoToPortal("HSP", "administrador", "user998871", "http://localhost/gpsnode/portal/ws/prepareSSO", ""http://192.168.1.56:8080/BOLDWeb/faces/admin/indexSSO.xhtml" );*/ } function gotoToPortal(origin, userName, personCode, urlWS, portalUrl) { var paramsSign = { origin: origin, destination: "BOLD PORTAL", functionCode: 0, userName: userName, personCode: personCode, companyCode: "", sessionInfo: {} // dummy session data }; // Pedimos los datos de autenticación $.ajax({ type: "POST", encoding: 'utf8', contentType: "application/json; charset=utf-8", url: urlWS, data: JSON.stringify(paramsSign), success: function(dataSSO){ if( !dataSSO.ok ) { alert( dataSSO.err ); return; } // Enviamos un POST a la URL del portal con los datos de autenticación postToUrl( portalUrl, { SSOParam: dataSSO.data }, true ); } }); } </script> </head> <body> <button type="button" onclick="connectSSO()">Conectar al portal</button> </body>
Básicamente lo que determina el procedimiento son los parámetros de la función gotoToPortal() que por este orden son:
- origin: identificador del portal origen
- userName: identificador de usuario con las credenciales actuales
- personCode: código de la persona en el programa de RR.HH. y que deberá corresponderse on un identificador en BOLD
- urlWS: url del webservice que retorna los parámetros de identificación codificados y encriptados (en esta documentación se incluye un ejemplo de posible implementación)
- portalUrl: url donde está el portal de BOLD (actualmente es
http://<URL_PORTAL>/faces/admin/indexSSO.xhtml
) - functionCode: se trata de un número entero que indicará la primera página que se mostrará al usuario tras la redirección. Ver la siguiente sección.
Configuración de la redirección: functionCode
Por defecto, la página que se le mostrará al usuario será la de datos personales. Pero es posible redirigirlo hacia otras páginas en función de este parámetro. Esta configuración reside en el fichero BoldWebCfg.xml (ver Configuración (portal del empleado)) en la sección opcional siguiente:
<SSOFunctionCodes> <![CDATA[ 2--redirect:w/personaldata.xhtml?pfriendly=true; 3--redirect:w/contractListSQL.xhtml?pfriendly=true; 4--redirect:plan/currentweek.xhtml?pfriendly=true; 5--redirect:plan/currentmonth.xhtml?pfriendly=true; 6--redirect:plan/printyearcalendar.xhtml?pfriendly=true; 7--redirect:w/anualcounters.xhtml?pfriendly=true; 8--redirect:w/incidencelist.xhtml?pfriendly=true; 9--redirect:forms/edit_form_enter_licenses_holidays.xhtml?pfriendly=true; 10--redirect:forms/my_tab_licenses_all.xhtml?pfriendly=true; 11--redirect:forms/edit_form_cancel_licenses_holidays.xhtml?pfriendly=true; 12--redirect:forms/cancel_my_tab_licenses_all.xhtml?pfriendly=true; 13--redirect:forms/tab_search_advanced.xhtml?Class=5&Type=0&pfriendly=true; ]]> </SSOFunctionCodes>
En el ejemplo anterior pasando un functionCode=6 enviará el usuario a la página con el calendario anual.
Nota: hay ciertas páginas (como la del buscador de formularios) a las que se rechazará redirigir a un usuario a menos que tenga un rol superior al de Empleado.
Implementación mínima necesaria en el portal origen
- Es necesario trasladar el código del ejemplo a la tecnología utilizada en el portal origen
- Habrá que reimplementar el webservice en urlWS en el portal origen (o copiar el código de su implementación ejemplo en nodejs)
Implementación del webservice urlWS en nodejs
Este webservice prepara la respuesta JSON (el código se apoya en algunas funciones complementarias no incluidas en la distribución estándard de nodejs):
router.post('/portal/ws/prepareSSO', function(req, res) { var origin = CCM.wsGetParam(req, res, "origin"); var destination = CCM.wsGetParam(req, res, "destination"); var functionCode = CCM.wsGetParamInt(req, res, "functionCode"); var userName = CCM.wsGetParam(req, res, "userName"); var personCode = CCM.wsGetParam(req, res, "personCode"); var companyCode = CCM.wsGetParam(req, res, "companyCode"); var destinationURL; if (destination === "BOLD PORTAL") { destinationURL = "https://BOLD:8081/boldweb"; } else { return CCM.wsReturnError(req, res, new Error("Invalid destination: " + destination), true); } var resultJSON = { origin: origin, destination: destination, destinationURL: destinationURL, data: { timestamp: (new Date()).toISOString(), userName: userName, companyCode: companyCode, personCode: personCode, functionCode: functionCode }, signature: "signatura del camp data en utilitzant RSA-SHA256", urlCert: "URL opcional del certificat X509" }; // Locate PK file var pkFile; if (origin === "TEST") pkFile = "test/test_data/privatekey.pem"; else pkFile = path.join(CCM.getBOLDWebCfgDir(req), origin + ".pem"); if (!BOLDXML_tools.fileExists(pkFile)) { logger.error("PK file not found! " + pkFile); return CCM.wsReturnError(req, res, new Error("SSO is not enabled for this origin: " + origin), true); } // Sign data var signature; try { resultJSON.signature = CertsMgr.signData(pkFile, JSON.stringify(resultJSON.data)); } catch (err) { logger.error("Exception signing data: " + err); var msgerr = "Key is not installed or is invalid!"; return CCM.wsReturnError(req, res, new Error(msgerr), true); } CCM.wsReturn(req, res, resultJSON); });
Función que efectúa la firma y encriptación del JSON de la respuesta
CertsMgr.signData = function(keyPEMFile, dataString) { var pem = fs.readFileSync(keyPEMFile); var key = pem.toString('ascii'); var sign = require('crypto').createSign('RSA-SHA256'); sign.update(dataString); var sig = sign.sign(key, 'hex'); return sig; };
Básicamente lee el fichero con la clave privada del certificado (.pem) y genera una firma digital sobre el parámetro string. Cuando el portal de BOLD reciba este paquete de datos, podrá verificar esta firma utilizando la clave pública del certificado complementario correspondiente.
Testing de la funcionalidad
La mejor forma es partir del fichero gpsnode/test/TestSSO.html y trazar dicho código. Desde aquí se puede probar con diferentes functionCode de forma sencilla.
Es importante destacar que solo los usuarios con acceso por LDAP se podrán validar con Single Sign On.
En el caso de usuarios únicamente definidos en BOLD, existe un procedimiento que sólo se habilitat durante las pruebas de desarrollo en java inyectando directamente en el código el password del usuario (ver UserBean::SSOExecute)
Generación de certificados para pruebas
Online certificate generator: https://infotechinc.github.io/create-x509-certificate/
Obtener un fichero .pfx (el que usa IIS o .NET) a partir de los ficheros anteriores: https://stackoverflow.com/questions/808669/convert-a-cert-pem-certificate-to-a-pfx-certificate
Herramientas openssl para manipular certificados: https://sourceforge.net/projects/openssl/