Compartir a través de


Personalización de notificaciones emitidas en JSON Web Token (JWT) para aplicaciones empresariales

La plataforma de identidad de Microsoft admite el inicio de sesión único (SSO) con la mayoría de las aplicaciones pre integradas en la galería de aplicaciones de Microsoft Entra y las aplicaciones personalizadas. Cuando un usuario se autentica en una aplicación a través de la plataforma de identidad de Microsoft mediante el protocolo OIDC, ésta envía un token a la aplicación. La aplicación valida el token y lo usa para que el usuario inicie sesión en lugar de solicitar un nombre de usuario y una contraseña.

Estas instancias de JSON Web Token (JWT) usadas por las aplicaciones OIDC y OAuth contienen información sobre el usuario conocido como notificaciones. Una notificación es información que un proveedor de identidades declara sobre un usuario dentro del token que se emite para dicho usuario. En una respuesta OIDC, los datos de notificaciones normalmente se incluyen en el token de id. emitido por el proveedor de identidades en forma de JWT.

Visualización o edición de notificaciones

Sugerencia

Los pasos de este artículo pueden variar ligeramente en función del portal desde donde comienza.

Para ver o editar las notificaciones emitidas en la instancia de JWT a la aplicación:

  1. Inicie sesión en el Centro de administración de Microsoft Entra como Administrador de aplicaciones en la nube.
  2. Vaya a Identidad> Aplicaciones>aplicaciones para empresas> Todas las aplicaciones.
  3. Seleccione la aplicación, seleccione Inicio de sesión único en el menú de la izquierda y, a continuación, seleccione Editar en la sección Atributos y notificaciones.

Una aplicación puede necesitar personalización de notificaciones por varios motivos. Por ejemplo, cuando una aplicación requiere un conjunto diferente de URI de notificación o valores de notificación. Con la sección Atributos y notificaciones, puede agregar o quitar una notificación para la aplicación. También puede crear una notificación personalizada específica para una aplicación en función del caso de uso.

En los pasos siguientes se describe cómo asignar un valor constante:

  1. Seleccione la notificación que desea modificar.
  2. Escriba el valor constante sin comillas en Atributo de origen según su organización y luego haga clic en Guardar.

La información general sobre atributos muestra el valor constante.

Transformaciones de notificaciones especiales

Puede usar las siguientes funciones de transformaciones de notificaciones especiales.

Función Descripción
ExtractMailPrefix() Quita el sufijo de dominio de la dirección de correo electrónico o el nombre principal de usuario. Esta función extrae solo la primera parte del nombre de usuario. Por ejemplo, joe_smith en lugar de joe_smith@contoso.com.
ToLower() Convierte los caracteres del atributo seleccionado en caracteres en minúscula.
ToUpper() Convierte los caracteres del atributo seleccionado en caracteres en mayúscula.

Incorporación de notificaciones específicas de la aplicación

Para agregar notificaciones específicas de la aplicación:

  1. En Atributos y notificaciones de usuario, seleccione Agregar nueva notificación para abrir la página Administrar las notificaciones del usuario.
  2. Escriba el nombre de las notificaciones. El valor no tiene que seguir un patrón de URI estrictamente. Si necesita un patrón de URI, puede colocarlo en el campo Espacio de nombres.
  3. Seleccione el origen en el que la notificación va a recuperar su valor. Puede seleccionar un atributo de usuario en la lista desplegable de atributos de origen o aplicar una transformación al atributo de usuario antes de emitirlo como una notificación.

Transformaciones de notificación

Para aplicar una transformación a un atributo de usuario:

  1. En Administrar notificaciones, seleccione Transformación como origen de la notificación para abrir la página Administrar la transformación.
  2. Seleccione la función en la lista desplegable transformación. Dependiendo de la función seleccionada, proporciona parámetros y un valor constante para evaluar en la transformación.
  3. Tratar el origen como multivalor indica si la transformación se aplica a todos los valores o solo al primero. De forma predeterminada, el primer elemento de una notificación de varios valores se aplica a las transformaciones. Al activar esta casilla, se asegura de que se aplica a todos. Esta casilla de verificación solo está habilitada para atributos de varios valores. Por ejemplo, user.proxyaddresses.
  4. Para aplicar varias transformaciones, seleccione Agregar transformación. Puede aplicar un máximo de dos transformaciones a una notificación. Por ejemplo, puede extraer primero el prefijo de correo del user.mail. Después, convierta la cadena en mayúsculas.

Puede utilizar las siguientes funciones para transformar notificaciones.

Función Descripción
ExtractMailPrefix() Quita el sufijo de dominio de la dirección de correo electrónico o el nombre principal de usuario. Esta función extrae solo la primera parte del nombre de usuario. Por ejemplo, joe_smith en lugar de joe_smith@contoso.com.
Join() Crea un nuevo valor al combinar dos atributos. Si quiere, puede usar un separador entre los dos atributos. Para la transformación de notificaciones NameID, la función Join() tiene un comportamiento específico cuando la entrada de la transformación tiene una parte del dominio. La función quita la parte de dominio de la entrada antes de unirla al separador y al parámetro seleccionado. Por ejemplo, si la entrada de la transformación es joe_smith@contoso.com, el separador @ y el parámetro fabrikam.com, esta combinación de entrada da como resultado joe_smith@fabrikam.com.
ToLowercase() Convierte los caracteres del atributo seleccionado en caracteres en minúscula.
ToUppercase() Convierte los caracteres del atributo seleccionado en caracteres en mayúscula.
Contains() Genera un atributo o una constante si la entrada coincide con el valor especificado. En caso contrario, puede especificar otra salida si no hay ninguna coincidencia.
Por ejemplo, si quieres emitir una notificación en la que el valor es la dirección de correo electrónico del usuario si contiene el dominio @contoso.com, en caso contrario, quieres obtener el nombre principal de usuario. Para realizar esta función, configure los valores siguientes:
Parámetro 1 (entrada) : user.email
Valor: "@contoso.com"
Parámetro 2 (salida): user.email
Parámetro 3 (salida si no hay ninguna coincidencia): user.userprincipalname
EndWith() Genera un atributo o una constante si la entrada finaliza con el valor especificado. En caso contrario, puede especificar otra salida si no hay ninguna coincidencia.
Por ejemplo, si quiere emitir una notificación en la que el valor es el id. de empleado del usuario, si el id. de empleado termina con 000; de lo contrario, se recomienda generar un atributo de extensión. Para realizar esta función, configure los valores siguientes:
Parámetro 1 (entrada) : user.employeeid
Valor: "000"
Parámetro 2 (salida): user.employeeid
Parámetro 3 (salida si no hay ninguna coincidencia): user.extensionattribute1
StartWith() Genera un atributo o una constante si la entrada empieza con el valor especificado. En caso contrario, puede especificar otra salida si no hay ninguna coincidencia.
Por ejemplo, si quiere emitir una notificación en la que el valor es el id. de empleado del usuario, si el país o la región comienza por US; de lo contrario, se recomienda generar un atributo de extensión. Para realizar esta función, configure los valores siguientes:
Parámetro 1 (entrada) : user.country
Valor: "US"
Parámetro 2 (salida): user.employeeid
Parámetro 3 (salida si no hay ninguna coincidencia): user.extensionattribute1
Extract(): después de la coincidencia Devuelve el valor de substring que aparece después de la coincidencia con el valor especificado.
Por ejemplo, si el valor de entrada es Finance_BSimon, el valor coincidente es Finance_, entonces la salida de la notificación es BSimon.
Extract(): antes de la coincidencia Devuelve el valor de substring que aparece antes de la coincidencia con el valor especificado.
Por ejemplo, si el valor de entrada es BSimon_US, el valor coincidente es _US, entonces la salida de la notificación es BSimon.
Extract(): entre coincidencias Devuelve el valor de substring que aparece antes de la coincidencia con el valor especificado.
Por ejemplo, si el valor de la entrada es Finance_BSimon_US, el primer valor coincidente es Finance_, el segundo valor coincidente es _US, entonces la salida de la notificación es BSimon.
ExtractAlpha(): prefijo Devuelve la parte alfabética del prefijo de la cadena.
Por ejemplo, si el valor de la entrada es BSimon_123, entonces devuelve BSimon.
ExtractAlpha(): sufijo Devuelve la parte alfabética del sufijo de la cadena.
Por ejemplo, si el valor de la entrada es 123_Simon, entonces devuelve Simon.
ExtractNumeric(): prefijo Devuelve la parte numérica del prefijo de la cadena.
Por ejemplo, si el valor de la entrada es 123_BSimon, entonces devuelve 123.
ExtractNumeric(): sufijo Devuelve la parte numérica del sufijo de la cadena.
Por ejemplo, si el valor de la entrada es BSimon_123, entonces devuelve 123.
IfEmpty() Genera un atributo o una constante si la entrada es nula o está vacía.
Por ejemplo, si quieres generar un atributo almacenado en un atributo de extensión si la ID de empleado de un usuario determinado está vacía. Para realizar esta función, configura los siguientes valores:
Parámetro 1 (entrada): user.employeeid
Parámetro 2 (salida): user.extensionattribute1
Parámetro 3 (salida si no hay ninguna coincidencia): user.employeeid
IfNotEmpty() Genera un atributo o una constante si la entrada no es nula ni está vacía.
Por ejemplo, si quieres generar un atributo almacenado en un atributo de extensión si la ID de empleado de un usuario determinado no está vacía. Para realizar esta función, configure los valores siguientes:
Parámetro 1 (entrada): user.employeeid
Parámetro 2 (salida): user.extensionattribute1
Substring(): longitud fija Extrae partes de un tipo de notificación de cadena, comenzando por el carácter que se encuentra en la posición especificada, y devuelve el número de caracteres especificado.
SourceClaim: el origen de notificación de la transformación que se debe ejecutar.
StartIndex: posición de carácter inicial de base cero de una substring en la instancia.
Length: longitud en caracteres de la substring.
Por ejemplo:
sourceClaim: PleaseExtractThisNow
StartIndex: 6
Length: 11
Output: ExtractThis
Substring() - EndOfString Extrae partes de un tipo de notificación de cadena, comenzando por el carácter que se encuentra en la posición especificada, y devuelve el resto de la notificación del índice de inicio especificado.
SourceClaim: el origen de notificación de la transformación.
StartIndex: posición de carácter inicial de base cero de una substring en la instancia.
Por ejemplo:
sourceClaim: PleaseExtractThisNow
StartIndex: 6
Output: ExtractThisNow
RegexReplace() La transformación RegexReplace() acepta como parámetros de entrada:
- Parámetro 1: un atributo de usuario como entrada de regex
- Una opción para confiar en el origen como multivalor
- Patrón de regex
- Patrón de reemplazo El patrón de reemplazo puede contener formato de texto estático junto con una referencia que apunte a los grupos de salida de expresión regular y más parámetros de entrada.

Si necesita otras transformaciones, envíe su idea al foro de comentarios de Microsoft Entra ID, en la categoría Aplicación SaaS.

Transformación de notificaciones basada en regex

En la imagen siguiente se muestra un ejemplo del primer nivel de transformación:

Captura de pantalla del primer nivel de transformación.

En la tabla siguiente se proporciona información sobre el primer nivel de transformaciones. Las acciones enumeradas en la tabla corresponden a las etiquetas de la imagen anterior. Seleccione Editar para abrir la hoja de transformación de reclamaciones.

Acción Campo Descripción
1 Transformation Seleccione la opción RegexReplace() en las opciones Transformación para usar el método de transformación de notificaciones basada en regex para transformación de notificaciones.
2 Parameter 1 Entrada de la transformación de expresión regular. Por ejemplo, user.mail que tiene una dirección de correo electrónico de usuario como admin@fabrikam.com.
3 Treat source as multivalued Algunos atributos de usuario de entrada pueden ser atributos de usuario de varios valores. Si el atributo de usuario seleccionado admite varios valores y el usuario quiere usar varios valores para la transformación, debe seleccione Tratar origen como multivalor. Si esta opción está seleccionada, se usan todos los valores para la coincidencia de regex; de lo contrario, solo se usa el primer valor.
4 Regex pattern Expresión regular que se evalúa con respecto al valor del atributo de usuario seleccionado como Parámetro 1. Por ejemplo, una expresión regular para extraer el alias de usuario de la dirección de correo electrónico del usuario se representa como (?'domain'^.*?)(?i)(\@fabrikam\.com)$.
5 Add additional parameter Se puede usar más de un atributo de usuario para la transformación. Los valores de los atributos se combinarían con la salida de transformación de regex. Se admiten hasta cinco parámetros más.
6 Replacement pattern El patrón de reemplazo es la plantilla de texto, que contiene marcadores de posición para el resultado de regex. Todos los nombres de grupo deben ir entre llaves, por ejemplo, {nombre-de-grupo}. Supongamos que la administración quiere usar el alias de usuario con algún otro nombre de dominio, por ejemplo, xyz.com y combinar el nombre del país con él. En este caso, el patrón de reemplazo sería {country}.{domain}@xyz.com, donde {country} es el valor del parámetro de entrada y {domain} es la salida del grupo de evaluación de expresiones regulares. En tal caso, el resultado esperado será US.swmal@xyz.com.

En la imagen siguiente se muestra un ejemplo del segundo nivel de transformación:

Captura de pantalla del segundo nivel de transformación de notificaciones.

En la tabla siguiente se proporciona información sobre el segundo nivel de transformaciones. Las acciones enumeradas en la tabla corresponden a las etiquetas de la imagen anterior.

Acción Campo Descripción
1 Transformation Las transformaciones de notificaciones basadas en regex no se limitan a la primera transformación y también se pueden usar como transformación de segundo nivel. Cualquier otro método de transformación se puede usar como primera transformación.
2 Parameter 1 Si se selecciona RegexReplace() como transformación de segundo nivel, la salida de la transformación de primer nivel se usa como entrada para la transformación de segundo nivel. Para aplicar la transformación, la expresión regular de segundo nivel debe coincidir con la salida de la primera transformación.
3 Regex pattern Patrón de regex es la expresión regular para la transformación de segundo nivel.
4 Parameter input Entradas de atributo de usuario para las transformaciones de segundo nivel.
5 Parameter input Los administradores pueden eliminar el parámetro de entrada seleccionado si ya no lo necesitan.
6 Replacement pattern El patrón de reemplazo es la plantilla de texto, que contiene marcadores de posición para el nombre del grupo de resultados de regex, el nombre del grupo de parámetros de entrada y el valor de texto estático. Todos los nombres de grupo deben ir entre llaves, como {group-name}. Supongamos que la administración quiere usar el alias de usuario con algún otro nombre de dominio, por ejemplo, xyz.com y combinar el nombre del país con él. En este caso, el patrón de reemplazo sería {country}.{domain}@xyz.com, donde {country} es el valor del parámetro de entrada y {domain} es la salida del grupo de evaluación de expresiones regulares. En tal caso, el resultado esperado será US.swmal@xyz.com.
7 Test transformation La transformación RegexReplace() solo se evalúa si el valor del atributo de usuario seleccionado para Parámetro 1 coincide con la expresión regular proporcionada en el cuadro de texto Patrón de regex. De lo contrario, se agrega el valor de notificación predeterminado al token. Para validar la expresión regular con el valor del parámetro de entrada, hay disponible una experiencia de prueba en la hoja de transformación. Esta experiencia de prueba solo funciona con valores ficticios. Cuando se usan los parámetros de entrada adicionales, el nombre del parámetro se agrega al resultado de la prueba en lugar de al valor real. Para acceder a la sección de prueba, seleccione Probar transformación.

En la imagen siguiente, se muestra un ejemplo de prueba de las transformaciones:

Captura de pantalla de la prueba de la transformación.

En la tabla siguiente se proporciona información sobre la prueba de las transformaciones. Las acciones enumeradas en la tabla corresponden a las etiquetas de la imagen anterior.

Acción Campo Descripción
1 Test transformation Seleccione el botón cerrar o botón con una cruz (X) para ocultar la sección de prueba y que aparezca de nuevo el botón Probar transformación en la hoja.
2 Test regex input Acepta la entrada que se usa para la evaluación de pruebas de expresiones regulares. Cuando una transformación de notificaciones basada en expresiones regulares se configura como una transformación de segundo nivel, proporciona un valor que sea el resultado esperado de la primera transformación.
3 Run test Una vez proporcionada la entrada de regex de prueba y configuradas las opciones Patrón de regex, Patrón de reemplazo y Parámetros de entrada, la expresión se puede evaluar seleccionando Ejecutar prueba.
4 Test transformation result Si la evaluación tiene éxito, se representa una salida de la transformación de prueba en la etiqueta de resultado de la transformación de prueba.
5 Remove transformation La transformación de segundo nivel se puede quitar seleccionando Quitar transformación.
6 Specify output if no match Cuando se configura un valor de entrada de regex con respecto al Parámetro 1, que no coincide con la Expresión regular, la transformación se omite. En tales casos, se puede configurar el atributo de usuario alternativo, el cual se agregará al token de la notificación activando la Especificar el resultado si no se encuentran coincidencias.
7 Parameter 3 Si es necesario devolver un atributo de usuario alternativo cuando no hay ninguna coincidencia y Especificar el resultado si no se encuentran coincidencias está activada, se puede seleccionar un atributo de usuario alternativo mediante la lista desplegable. Esta lista desplegable está disponible en Parámetro 3 (resultado si no hay coincidencias).
8 Summary En la parte inferior de la hoja, se muestra el resumen completo del formato, que explica el significado de la transformación en texto simple.
9 Add Una vez comprobadas las opciones de configuración de la transformación, se puede guardar en una directiva de notificaciones seleccionando Agregar. Selecciona Guardar en la hoja Administrar notificación para guardar los cambios.

La transformación RegexReplace() también está disponible para las transformaciones de notificaciones de grupo.

Validaciones de transformación

Un mensaje proporciona más información cuando se producen las condiciones siguientes después de seleccionar Agregar o Ejecutar prueba:

  • Se utilizaron parámetros de entrada con atributos de usuario duplicados.
  • Se encontraron parámetros de entrada sin usar. Los parámetros de entrada definidos deben tener un uso respectivo en el texto del patrón de reemplazo.
  • La entrada de regex de prueba proporcionada no coincide con la expresión regular proporcionada.
  • No se encuentran orígenes para los grupos en el patrón de reemplazo.

Emisión de notificaciones basadas en condiciones

Puede especificar el origen de una notificación en función del tipo de usuario y el grupo al que pertenece el usuario.

El tipo de usuario puede ser:

  • Cualquiera: todos los usuarios pueden tener acceso a la aplicación.
  • Miembros: Miembro nativo del inquilino
  • Todos los invitados: el usuario se movió de una organización externa con o sin Microsoft Entra ID.
  • Invitados de Microsoft Entra: el usuario invitado pertenece a otra organización mediante Microsoft Entra ID.
  • Invitados externos: el usuario invitado pertenece a una organización externa que no tiene Microsoft Entra ID.

Un escenario en el que el tipo de usuario resulta útil es cuando el origen de una notificación es diferente para un invitado y para un empleado que tiene acceso a una aplicación. Puedes especificar que, si el usuario es un empleado, obtén el NameID de user.email. Si el usuario es un invitado, el NameID proviene de user.extensionattribute1.

Para agregar una condición de notificaciones:

  1. En Administrar notificaciones, expanda las Condiciones de la notificación.
  2. Seleccione el tipo de usuario.
  3. Seleccione los grupos a los que debe pertenecer el usuario. Puede seleccionar hasta 50 grupos únicos en todas las notificaciones para una aplicación determinada.
  4. Seleccione el origen en el que la notificación va a recuperar su valor. Puede seleccionar un atributo de usuario en la lista desplegable de atributos de origen o aplicar una transformación al atributo de usuario antes de emitirlo como una notificación.

El orden en que se agregan las condiciones es importante. En primer lugar, Microsoft Entra evalúa todas las condiciones con el origen Attribute y, a continuación, evalúa todas las condiciones con el origen Transformation para decidir qué valor emitir en la notificación. Microsoft Entra ID evalúa las condiciones con el mismo origen de arriba a abajo. La notificación emite el último valor que coincide con la expresión de la notificación. Transformaciones como IsNotEmpty y Contains actúan como restricciones.

Por ejemplo, Britta Simon es un usuario invitado en el suscriptor de Contoso. Britta pertenece a otra organización que también usa Microsoft Entra ID. Dada la siguiente configuración para la aplicación de Fabrikam, cuando Britta intenta iniciar sesión en Fabrikam, la Plataforma de identidad de Microsoft evalúa las condiciones.

En primer lugar, la Plataforma de identidad de Microsoft comprueba si el tipo de usuario de Britta es Todos los invitados. Dado que el tipo de usuario es Todos los invitados, la plataforma de identidad de Microsoft asigna el origen de la notificación a user.extensionattribute1. En segundo lugar, la Plataforma de identidad de Microsoft comprueba si el tipo de usuario de Britta es Invitados de Microsoft Entra. Dado que el tipo de usuario es Todos los invitados, la plataforma de identidad de Microsoft asigna el origen de la notificación a user.mail. Por último, la notificación se emite con un valor de user.mail para Britta.

Como otro ejemplo, considera cuando Britta Simon intenta iniciar sesión con la siguiente configuración. En primer lugar,Microsoft Entra evalúa todas las condiciones con el origen Attribute. El origen de la notificación es user.mail cuando el tipo de usuario de Britta es invitados de Microsoft Entra. A continuación, Microsoft Entra ID evalúa las transformaciones. Dado que Britta es un invitado, user.extensionattribute1 es el nuevo origen de la notificación. Dado que Britta está en Invitados de Microsoft Entra, user.othermailes el nuevo origen de esta notificación. Por último, la notificación se emite con un valor de user.othermail para Britta.

Como ejemplo final, veamos lo que sucede si Britta no tiene configurado user.othermail o está vacío. La notificación vuelve a user.extensionattribute1 ignorando la entrada de condición en ambos casos.

Consideraciones sobre la seguridad

Las aplicaciones que reciben tokens confían en los valores que no pueden ser manipulados. Al modificar el contenido de los tokens mediante la personalización de las notificaciones, estas suposiciones pueden dejar de ser correctas. Las aplicaciones deben reconocer explícitamente que los tokens han sido modificados para protegerse de las personalizaciones creadas por actores malintencionados. Proteja frente a personalizaciones inapropiadas de una de las maneras siguientes:

Sin esto, Microsoft Entra ID devuelve un código de error AADSTS50146.

Configurar una clave de firma personalizada

Para aplicaciones multi inquilino, se debe utilizar una clave de firma personalizada. No establezca acceptMappedClaims en el manifiesto de la aplicación. Al configurar una aplicación en el portal de Azure, se obtiene un objeto de registro de aplicación y un servicio principal en el inquilino. Esa aplicación usa la clave de inicio de sesión global de Azure, que no se puede usar para personalizar las notificaciones en los tokens. Para obtener notificaciones personalizadas en los tokens, cree una clave de inicio de sesión personalizada a partir de un certificado y agréguela a la entidad de servicio. Para fines de prueba, puede usar un certificado autofirmado. Después de configurar la clave de firma personalizada, el código de la aplicación debe validar la clave de firma de token.

Agregue la siguiente información a la entidad de servicio:

Extraiga las claves pública y privada codificadas en base 64 de la exportación de archivos PFX del certificado. Asegúrese de que el valor keyId de keyCredential que se usa para "Sign" coincide con el valor keyId de passwordCredential. Puede generar el customkeyIdentifier obteniendo el hash de la huella digital del certificado.

Solicitud

Nota:

En primer lugar, deshabilite cualquier configuración de bloqueo de entidad de servicio en las aplicaciones recién creadas desde la hoja registros de aplicaciones del centro de administración de Microsoft Entra antes de intentar realizar un PATCH en la entidad de servicio, lo que da lugar a una solicitud incorrecta 400.

El siguiente ejemplo muestra el formato de la solicitud HTTP PATCH para agregar una clave de firma personalizada a una entidad de servicio. El valor "key" de la propiedad keyCredentials se acorta para mejorar la legibilidad. El valor está codificado en base 64. En la clave privada, el uso de la propiedad es Sign. En la clave pública, el uso de la propiedad es Verify.

PATCH https://graph.microsoft.com/v1.0/servicePrincipals/aaaaaaaa-bbbb-cccc-1111-222222222222

Content-type: servicePrincipals/json
Authorization: Bearer {token}

{
    "keyCredentials":[
        {
            "customKeyIdentifier": "aB1cD2eF3gH4iJ5kL6-mN7oP8qR=", 
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "aaaaaaaa-0b0b-1c1c-2d2d-333333333333",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "X509CertAndPassword",
            "usage": "Sign",
            "key":"cD2eF3gH4iJ5kL6mN7-oP8qR9sT==",
            "displayName": "CN=contoso"
        },
        {
            "customKeyIdentifier": "aB1cD2eF3gH4iJ5kL6-mN7oP8qR=",
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "bbbbbbbb-1c1c-2d2d-3e3e-444444444444",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "AsymmetricX509Cert",
            "usage": "Verify",
            "key": "cD2eF3gH4iJ5kL6mN7-oP8qR9sT==",
            "displayName": "CN=contoso"
        }

    ],
    "passwordCredentials": [
        {
            "customKeyIdentifier": "aB1cD2eF3gH4iJ5kL6-mN7oP8qR=",
            "keyId": "cccccccc-2d2d-3e3e-4f4f-555555555555",
            "endDateTime": "2022-01-27T19:40:33Z",
            "startDateTime": "2020-04-20T19:40:33Z",
            "secretText": "mypassword"
        }
    ]
}

Configurar una clave de firma personalizada con PowerShell

Use PowerShell para crear instancias de una aplicación cliente pública de MSAL y usar el flujo de concesión de código de autorización para obtener un token de acceso de permiso delegado para Microsoft Graph. Use el token de acceso para llamar a Microsoft Graph y configurar una clave de firma personalizada para la entidad de servicio. Después de configurar la clave de firma personalizada, el código de la aplicación debe validar la clave de firma de token.

Para ejecutar el script, necesita lo siguiente:

  • El Id. de objeto de la entidad de seguridad de servicio de su aplicación, que se encuentra en la hoja Información general de la entrada de su aplicación en Aplicaciones empresariales en el Azure portal.
  • Un registro de la aplicación para iniciar la sesión de un usuario y obtener un token de acceso para llamar a Microsoft Graph. Obtenga el identificador de esta aplicación (cliente) en la hoja Información general de la entrada de la aplicación en Registros de aplicaciones en Azure Portal. El registro de la aplicación debe tener la configuración siguiente:
    • Un identificador URI de redireccionamiento de "http://localhost"", que aparece en la configuración de la plataforma Aplicaciones móviles y de escritorio.
    • En Permisos de API, los permisos delegados de Microsoft Graph Application.ReadWrite.All y User.Read (asegúrese de conceder consentimiento del administrador a estos permisos).
  • Un usuario que inicie sesión para obtener el token de acceso de Microsoft Graph. El usuario debe tener uno de los siguientes roles administrativos de Microsoft Entra (necesarios para actualizar la entidad de servicio):
    • Administrador de aplicaciones en la nube
    • Administrador de aplicaciones
  • Un certificado que se configurará como clave de firma personalizada para nuestra aplicación. Puede crear un certificado autofirmado o bien obtener uno de la entidad de certificación de confianza. En el script se usan los componentes del certificado siguientes:
    • clave pública (normalmente un archivo .cer)
    • clave privada en formato PKCS#12 (en archivo .pfx)
    • contraseña de la clave privada (archivo .pfx)

Importante

La clave privada debe estar en formato PKCS #12, ya que Microsoft Entra ID no admite otros tipos de formato. Si se usa un formato incorrecto, puede producirse un error de tipo "Certificado no válido: el valor de la clave es un certificado no válido" al usar Microsoft Graph para aplicar PATCH a la entidad de servicio con un keyCredentials que contenga la información del certificado.

$fqdn="fourthcoffeetest.onmicrosoft.com" # this is used for the 'issued to' and 'issued by' field of the certificate
$pwd="mypassword" # password for exporting the certificate private key
$location="C:\\temp" # path to folder where both the pfx and cer file will be written to

# Create a self-signed cert
$cert = New-SelfSignedCertificate -certstorelocation cert:\currentuser\my -DnsName $fqdn
$pwdSecure = ConvertTo-SecureString -String $pwd -Force -AsPlainText
$path = 'cert:\currentuser\my\' + $cert.Thumbprint
$cerFile = $location + "\\" + $fqdn + ".cer"
$pfxFile = $location + "\\" + $fqdn + ".pfx"
 
# Export the public and private keys
Export-PfxCertificate -cert $path -FilePath $pfxFile -Password $pwdSecure
Export-Certificate -cert $path -FilePath $cerFile

$ClientID = "<app-id>"
$loginURL       = "https://login.microsoftonline.com"
$tenantdomain   = "fourthcoffeetest.onmicrosoft.com"
$redirectURL = "http://localhost" # this reply URL is needed for PowerShell Core 
[string[]] $Scopes = "https://graph.microsoft.com/.default"
$pfxpath = $pfxFile # path to pfx file
$cerpath = $cerFile # path to cer file
$SPOID = "<service-principal-id>"
$graphuri = "https://graph.microsoft.com/v1.0/serviceprincipals/$SPOID"
$password = $pwd  # password for the pfx file
 
 
# choose the correct folder name for MSAL based on PowerShell version 5.1 (.Net) or PowerShell Core (.Net Core)
 
if ($PSVersionTable.PSVersion.Major -gt 5)
    { 
        $core = $true
        $foldername =  "netcoreapp2.1"
    }
else
    { 
        $core = $false
        $foldername = "net45"
    }
 
# Load the MSAL/microsoft.identity/client assembly -- needed once per PowerShell session
[System.Reflection.Assembly]::LoadFrom((Get-ChildItem C:/Users/<username>/.nuget/packages/microsoft.identity.client/4.32.1/lib/$foldername/Microsoft.Identity.Client.dll).fullname) | out-null
  
$global:app = $null
  
$ClientApplicationBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientID)
[void]$ClientApplicationBuilder.WithAuthority($("$loginURL/$tenantdomain"))
[void]$ClientApplicationBuilder.WithRedirectUri($redirectURL)
 
$global:app = $ClientApplicationBuilder.Build()
  
Function Get-GraphAccessTokenFromMSAL {
    [Microsoft.Identity.Client.AuthenticationResult] $authResult  = $null
    $AquireTokenParameters = $global:app.AcquireTokenInteractive($Scopes)
    [IntPtr] $ParentWindow = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle
    if ($ParentWindow)
    {
        [void]$AquireTokenParameters.WithParentActivityOrWindow($ParentWindow)
    }
    try {
        $authResult = $AquireTokenParameters.ExecuteAsync().GetAwaiter().GetResult()
    }
    catch {
        $ErrorMessage = $_.Exception.Message
        Write-Host $ErrorMessage
    }
     
    return $authResult
}
  
$myvar = Get-GraphAccessTokenFromMSAL
if ($myvar)
{
    $GraphAccessToken = $myvar.AccessToken
    Write-Host "Access Token: " $myvar.AccessToken
    #$GraphAccessToken = "eyJ0eXAiOiJKV1QiL ... iPxstltKQ"
    
 
    #  this is for PowerShell Core
    $Secure_String_Pwd = ConvertTo-SecureString $password -AsPlainText -Force
 
    # reading certificate files and creating Certificate Object
    if ($core)
    {
        $pfx_cert = get-content $pfxpath -AsByteStream -Raw
        $cer_cert = get-content $cerpath -AsByteStream -Raw
        $cert = Get-PfxCertificate -FilePath $pfxpath -Password $Secure_String_Pwd
    }
    else
    {
        $pfx_cert = get-content $pfxpath -Encoding Byte
        $cer_cert = get-content $cerpath -Encoding Byte
        # Write-Host "Enter password for the pfx file..."
        # calling Get-PfxCertificate in PowerShell 5.1 prompts for password
        # $cert = Get-PfxCertificate -FilePath $pfxpath
        $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxpath, $password)
    }
 
    # base 64 encode the private key and public key
    $base64pfx = [System.Convert]::ToBase64String($pfx_cert)
    $base64cer = [System.Convert]::ToBase64String($cer_cert)
 
    # getting id for the keyCredential object
    $guid1 = New-Guid
    $guid2 = New-Guid
 
    # get the custom key identifier from the certificate thumbprint:
    $hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
    $hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($cert.Thumbprint))
    $customKeyIdentifier = [System.Convert]::ToBase64String($hash)
 
    # get end date and start date for our keycredentials
    $endDateTime = ($cert.NotAfter).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
    $startDateTime = ($cert.NotBefore).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
 
    # building our json payload
    $object = [ordered]@{    
    keyCredentials = @(       
         [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid1
            startDateTime = $startDateTime 
            type = "X509CertAndPassword"
            usage = "Sign"
            key = $base64pfx
            displayName = "CN=fourthcoffeetest" 
        },
        [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid2
            startDateTime = $startDateTime 
            type = "AsymmetricX509Cert"
            usage = "Verify"
            key = $base64cer
            displayName = "CN=fourthcoffeetest"   
        }
        )  
    passwordCredentials = @(
        [ordered]@{
            customKeyIdentifier = $customKeyIdentifier
            keyId = $guid1           
            endDateTime = $endDateTime
            startDateTime = $startDateTime
            secretText = $password
        }
    )
    }
 
    $json = $object | ConvertTo-Json -Depth 99
    Write-Host "JSON Payload:"
    Write-Output $json
 
    # Request Header
    $Header = @{}
    $Header.Add("Authorization","Bearer $($GraphAccessToken)")
    $Header.Add("Content-Type","application/json")
 
    try 
    {
        Invoke-RestMethod -Uri $graphuri -Method "PATCH" -Headers $Header -Body $json
    } 
    catch 
    {
        # Dig into the exception to get the Response details.
        # Note that value__ is not a typo.
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
        Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
    }
 
    Write-Host "Complete Request"
}
else
{
    Write-Host "Fail to get Access Token"
}

Validar la clave de firma de tokens

Las aplicaciones que tienen habilitada la asignación de notificaciones deben validar sus claves de firma de tokens mediante la anexión de appid={client_id} a las solicitudes de metadatos de OpenID Connect. El siguiente ejemplo muestra el formato del documento de metadatos de OpenID Connect que debe usar:

https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration?appid={client-id}

Actualización del manifiesto de aplicación

Para las aplicaciones de inquilino único, puede establecer la propiedad acceptMappedClaims en true en el manifiesto de aplicación. Como se documenta en el apiApplicationtipo de recurso. Establecer la propiedad permite que una aplicación use la asignación de notificaciones sin especificar ninguna clave de firma personalizada.

Advertencia

No establezca la propiedad acceptMappedClaims en true en aplicaciones multiinquilino, ya que puede permitir a agentes malintencionados crear directivas de asignación de reclamaciones para su aplicación.

Es necesario que el público del token solicitado use un nombre de dominio verificado de su inquilino de Microsoft Entra, lo que significa que debe establecer el Application ID URI (representado por el identifierUris en el manifiesto de la aplicación) por ejemplo a https://contoso.com/my-api o (simplemente usando el nombre de inquilino predeterminado)https://contoso.onmicrosoft.com/my-api.

Si no está usando un dominio verificado, Microsoft Entra devuelve un código de error AADSTS501461 con el mensaje "_AcceptMappedClaims solo se admite para un público de tokens que coincida con el GUID de la aplicación o un público dentro de los dominios verificados del inquilino". Cambie el identificador de recurso o use una clave de firma específica de la aplicación".

Opciones de notificaciones avanzadas

Configura las opciones de notificaciones avanzadas para que las aplicaciones OIDC expongan la misma notificación que los tokens SAML. También para aplicaciones que pretenden usar el mismo reclamo para tokens de respuesta SAML2.0 y OIDC.

Configura las opciones de reclamos avanzados marcando la casilla debajo de Opciones de notificaciones avanzadas en la hoja Administrar notificaciones.