Alertas de seguridad del usuario invitado

Resultado de imagen para open door

Salesforce lleva algunos meses invitándonos a alinearnos a las actualizaciones de seguridad del usuario invitado para sitios públicos (sites, portales y comunidades).

Una vez se activen las nuevas reglas, los sitios publicos deberan seguir las siguientes politicas:

  • El módelo de seguridad para usuarios invitados será Privado
  • Los usuarios invitados solo podran tener máximo permiso de Leer y Crear en cualquier objeto
  • Las nuevas reglas de colaboración para usuarios invitados serán los únicos mecanismos para dar acceso a registros y el permiso será máximo de Lectura.
  • El usuario invitado no podrá ser el propietario de ningun registro
  • El usuario invitado no tendrá permisos de Actualizar ni Borrar en ningún objeto
  • El usuario invitado ya no podrá tener el permiso “Ver todos los Usuarios
  • El usuario invitado ya no podrá tener el permiso “Ver todos los datos” ni “Modificar todos los datos

¿Cuándo entrarán en vigencia los cambios?

Para Marzo de 2020 ya se deben haber tenido en cuenta todas las indicaciones y haber tomado acción. En este mes empezaran a vencerse las fechas máximas y posterior al release Spring’20, las nuevas características no se podrán deshabilitar.

Hasta tanto se podrá mantener desactivado el permiso Proteger acceso de registro de usuario invitado, disponible en Configuración de colaboración

¿Como prepararse?

  • Seguir los pasos que se indican en las Alertas de Seguridad

Más información en el siguiente link Guest User Access Report – Managed

¿Qué son las reglas de colaboración de usuario invitado?

Para cada usuario invitado (existe uno por cada site, portal o comunidad) se deberan crear reglas de colaboración que permitean dar el permiso de lectura por cada objeto que se requiera.

Esta es una nueva funcionalidad disponible con está actualización

¿Como permitir al usuario invitado Actalizar y Borrar?

En este caso la solución parece sencilla. Para que desde un site publico, se puedan seguir Actualizando y Eliminando registros, lo que se debe hacer es ejecutar el codigo de Apex en modo del sistema es decir con la palabra reservada “without sharing”.

Con with sharing la clase no podra realizar actualizaciones ni eliminaciones

Al ser invocada por un usuario invitado, la recomendación es usar without sharing

¿Cómo reasignar propietario a los registros cuando los crea el Usuario Invitado?

Si hablamos de comunidad, desde Winter’20 existe la opción de reasignar los registros del usuario invitado al usuario por defecto de la Comunidad

después de activar está nueva opción, en la administración de la comunidad en Preferencias veremos la opción de relacionar el usuario por defecto que será el propietario de los registros de la comunidad

Para sites, está opción no existe y por lo tanto se debe actualizar la lógica de creación para asignar un propietario teniendo en cuenta que este usuario no se vaya a desactivar nunca, o empezaría a fallar la creación de registros.

¿Cómo validar?

Las alertas de seguridad se pueden activar/desactivar en un ambiente de sandbox a voluntad hasta antes de la fecha limite en Marzo.

En el siguinte link se puede ver un plan de pruebas (en inglés)

Plan de pruebas – Seguridad del Usuario Invitado

¿Donde encontrar más ayuda?

Como modificar un batch que se encuentra programado sin detener la programación

Aquellos que han hecho un batch en Apex y lo han programado saben que al momento de querer modificarlo en producción, por ejemplo a través de un conjunto de cambios, siempre nos encontramos con el mensaje

This Apex class has batch or future jobs pending or in progress

o en español

Esta clase programable tiene trabajos pendientes o en curso

La solucion rápida es desprogramar el trabajo. Implementar el conjunto de cambios y volver a reprogramar. Tan solo que algunas veces no sabemos que clase especificamente es la que está programada o se nos olvida revisar la configuración exacta que tenia la programación antes de eliminarla. Problemas que se solucionan con un poco de paciencia y cuidado.

Image result for patience free image"

Aunque desde el release Winter ’15 existe la opción de poder implementar clases que tengan trabajos pendientes o en curso

Ir a Configuración -> Ajustes de implementación

Si queremos tener mas control sobre que clases pueden implementarse cuando hay programaciones en curso, podemos utilizar otro enfoque, uno que en sus días fue explicado por Dan Appleman y hace uso entre otros del concepto de Reflexión en Apex.

Ver: Intriguing Design Pattern for Scheduled APEX

Reflexión en Apex

La capacidad de un programa de modificar su estructura de manera dinámica es conocido en otros lenguajes como Reflexión. En Apex contamos con la clase Type pero en otros lenguajes hay mas herramientas.

La solución explicada por Dan consiste en crear una clase programable (que no se va a modificar posteriormente)

Esta clase que implementa Schedulable declara su propia interfaz que es igual en su definición a la de una clase programable.

El secreto está en el uso de la clase Type que con su método forName, nos permite crear una instancia de nuestra clase Batch (o cualquier otra que deseemos programar) en tiempo de ejecución, por lo que la clase programable no sabrá que clase es, hasta que se ejecute.

Así podremos modificar nuestra clase posterior a que se encuentre programada

La clase que vamos a programar sería asi

Simplemente implementa la interfaz que definimos dentro de nuestra clase programable.

Para mas información de la clase Type ver Apex Developer Guide: Type Class

Permisos personalizados y reglas de validación mas sencillas

El dia de hoy vamos a conocer una funcionalidad un poco subutilizada que nos ofrece la plataforma. Son los Permisos personalizados.

Contexto

Un perfil está compuesto por casillas de seleccion que dan acceso a funcionalidades especificas. Por ejemplo, el permiso API activada

o el permiso Ver todos los datos

Hay situaciones donde quisieramos poder contar con un permiso como Modificar fecha de cierre de la oportunidad, y asignarselo solo a los usuarios indicados.

Normalmente este requirimiento de negocio, se aborda con una regla de validación como la siguiente

Vemos que se valida si el campo ya estaba lleno y si se está modificando

NOT(ISBLANK(PRIORVALUE(CloseDate))) && ISCHANGED(CloseDate) 

Y se pregunta si el perfil del usuario realizando la acción se llama Administrador del sistema

$Profile.Name <> 'Administrador del sistema'

Está es una solución completamente valida, pero empieza a presentar algunos incovenientes.

  • Qué pasa si se deben autorizar mas perfiles o usuarios especificos
  • Qué pasa si la instancia es multilenguaje.

Si se van a agregar mas perfiles, la regla podria terminar viendose así:

NOT(ISBLANK(PRIORVALUE(CloseDate)))&&
ISCHANGED(CloseDate) &&
$Profile.Name <> 'Administrador del sistema' &&
$Profile.Name <> 'Administrador del contrato' &&
$Profile.Name <> 'Administrador de soluciones' &&
$Profile.Name <> 'Custom: Support Profile' &&
$Profile.Name <> 'Gold Partner User' &&
$Profile.Name <> 'Partner Community User'

Y que al pasar el tiempo, podría crecer en longitud acercandose al límite de 5000 caracteres.

Si la instancia es multilenguaje, el nombre de los perfiles estándar se traduce al cambiar el idioma de la instancia, algo que no debería ocurrir con frecuencia, pero que al poder presentarse haría que Administrador del sistema se convierta en System Administrator y la regla de validación deje de funcionar.

Cómo usar permisos personalizados

En esta entrada proponemos una solución que tiene en cuenta estos escenarios y permite ser escalable facilmente.

Empezamos creando el permiso personalizado.

Vamos a configuración, y escribimos en busqueda rápida, Permisos personalizados

Seleccionamos y damos click en nuevo

Asignamos una valor en Etiqueta que sea corto y descriptivo y en el campo descripción explicamos su uso. Podemos seguir el ejemplo que vimos con el permiso API Activada .

Damos guardar.

Ya contamos con un permiso que podemos usar en la regla de validación.

Al volver a la regla, y dar click en insertar campo, en la sección Permission, vamos a encontrar nuestro permiso personalizado.

Y nuestra fórmula va a quedar así

NOT(ISBLANK(PRIORVALUE(CloseDate)))&&
ISCHANGED(CloseDate) &&
NOT($Permission.Modificar_Fecha_Cierre_Oportunidad)

Ahora solo nos resta, asignar este permiso a los perfiles que necesitemos. Es aqui donde vemos el poder de los permisos personalizados.

Para esto vamos al perfil, y damos click en Permisos personalizados, como se ve en la imagen

Para asignarlo, damos click en modificar y lo pasamos de la sección de Permisos personalizados disponibles a la de Permisos personalizados activados

Ahora nuestra sencilla expresión

$Permission.Modificar_Fecha_Cierre_Oportunidad

Devolvera verdadero si el perfil del usuario tiene este permiso y falso de lo contrario.

Podemos asignar este permiso a cuanto perfil deseamos, y automaticamente los usuarios con este perfil podrán, en este caso, cambiar la fecha de cierre de las oportunidades y nuestra regla de validación no tuvo que ser modificada.

Notas

  • Si deseamos asignar el permiso a un usuario específico y no a todos los de un perfil, podemos crear un conjunto de permisos y agregar de la misma manera que vimos con el perfil, el permiso al conjunto de permisos, y luego asignar el conjunto de permisos al usuario en particular.
  • Podemos validar permisos personalizados tambien a nivel de visualforce usando el campo de combinación global $Permission seguido del nombre API del permiso.
<apex:pageBlock rendered="{!$Permission.nombre_api_permiso}">
   <!-- Sección que solo se mostrará a los usuarios con el permiso adecuado-->
</apex:pageBlock>
  • Podemos validar permisos a nivel de Apex, usando el método FeatureManagement.checkPermission y pasando el nombre API del permiso
Boolean tienePermiso = FeatureManagement.checkPermission('<nombre_api_permiso>');

if (tienePermiso) {
    // Ejecutar código
}

Cómo Obtener set de Ids de Lupas en una sola línea de código

En el post anterior vimos como obtener los Ids de una lista de SObjects en una sola línea de código. Sin embargo ese método solo permitía hacerlo con el Id del SObject, es decir si la lista era de Oportunidades podiamos obtener los Ids de esas oportunidades.

Es muy frecuente que cuando escribimos un trigger queramos procesar los registros padre de los que entraron al trigger, por ejemplo, tenemos un trigger de oportunidades pero vamos a actualizar las cuentas de esas oportunidades.

En este caso el método tradicional es iterar sobre la lista del triggerNew e ir agregando a un set de Ids, el Id de cada Cuenta

Sin embargo al igual que en la entrada anterior se puede lograr en un línea de código y adicional con más eficiencia en términos de tiempo de CPU

En esta ocasion volvemos a utilizar el constructor de Map, que nos crea un Mapa con el Id del SObject como llave (el cual extraemos con el método keySet() al final). La diferencia es que el SObject ahora es un AggregateResult que se obtiene de agrupar la lista por el campo lupa que nos interesa.

Es muy importante a la hora de hacer el query colocarle el alias Id al campo lupa. De lo contrario se obtiene una excepción.

Solo funciona “Id” con I en mayuscula. “id” todo en minuscula generaria error tambien. Esto es un bug de la plataforma.

Cómo Obtener set de Ids en una sola linea de código

Una tarea relativamente frecuente al programar en Apex consiste en obtener un set Ids para pasar como parametro a una consulta en SOQL para realizar un procesamiento de ciertos registros.

Esta tarea que consiste en obtener los Ids de los registros a procesar intuitivamente se puede pensar como realizar un ciclo for para ir agregando a un set que luego pasaremos a la consulta de SOQL

Sin embargo esto se puede lograr en una sola línea usando el constructor de map que recibe una lista de SObject

Esta solución solo funciona para obtener un set de Ids del tipo de SObject de la lista. En una próxima entrada veremos como se puede usar una sola linea de codigo para obtener un set de Ids pero los Ids de una relacion de busqueda o maestro detalle de nuestra lista. Por ejemplo los Ids de las cuentas asociadas a las oportunidades anteriores.