Incorporación de inicio de sesión con Azure Active Directory B2C a una aplicación web de Spring

En este artículo se muestra cómo crear una aplicación de Java con la funcionalidad de inicio de sesión mediante Spring Initializr con spring Boot Starter para el id. de Microsoft Entra.

En este tutorial, aprenderá a:

  • Crear una aplicación de Java mediante Spring Initializr
  • Configurar Azure Active Directory B2C
  • Proteger la aplicación con las clases y anotaciones de Spring Boot
  • Compilar y probar la aplicación de Java

Microsoft Entra ID es la solución de identidad empresarial de escala de nube de Microsoft. Azure Active Directory B2C complementa el conjunto de características de Microsoft Entra ID, lo que le permite administrar el acceso de cliente, consumidor y ciudadano a las aplicaciones de negocio a consumidor (B2C).

Requisitos previos

Importante

Se requiere Spring Boot versión 2.5 o posterior para completar los pasos descritos en este artículo.

Creación de una aplicación con Spring Initialzr

  1. Vaya a https://start.spring.io/.

  2. Rellene los valores de acuerdo con esta guía. Las etiquetas y el diseño pueden diferir de la imagen que se muestra aquí.

    • En Proyecto, seleccione Proyecto de Maven.
    • En Lenguaje, seleccione Java.
    • En Spring Boot, seleccione 2.7.11.
    • En Grupo, Artefacto y Nombre, escriba el mismo valor usando una cadena descriptiva breve. La interfaz de usuario puede rellenar automáticamente algunos de estos campos a medida que escribe.
    • En el panel Dependencias, seleccione Agregar dependencias. Use la interfaz de usuario para agregar dependencias en Spring Web y Spring Security.

    Nota:

    Las versiones  5.5.1, 5.4.7, 5.3.10 y 5.2.11 de Spring Security se han publicado para abordar el siguiente informe CVE CVE-2021-22119: ataque por denegación de servicio con spring-security-oauth2-client. Si usa la versión anterior, actualícela.

  3. Seleccione Generar proyecto y descargue el proyecto en una ruta de acceso del equipo local. Mueva el archivo descargado a un directorio que se llame como el proyecto y descomprima el archivo. El diseño del archivo tendrá un aspecto similar al siguiente, con el valor especificado para Grupo en lugar de yourProject.

    .
    ├── HELP.md
    ├── mvnw
    ├── mvnw.cmd
    ├── pom.xml
    └── src
        ├── main
        │   ├── java
        │   │   └── yourProject
        │   │       └── yourProject
        │   │           └── YourProjectApplication.java
        │   └── resources
        │       ├── application.properties
        │       ├── static
        │       └── templates
        └── test
            └── java
                └── yourProject
                    └── yourProject
                        └── YourProjectApplicationTests.java
    

Creación e inicialización de una instancia de Microsoft Entra

Creación de la instancia de Active Directory

  1. Inicie sesión en https://portal.azure.com.

  2. Seleccione Crear un recurso. Busque Azure Active Directory B2C.

    Cree una instancia de Azure Active Directory B2C mediante Azure Portal.

  3. Seleccione Crear.

    Entrada de Azure Marketplace para Azure Active Directory B2C.

  4. Seleccione Crear un nuevo inquilino de Azure AD B2C.

    Opción de Azure Portal para crear un nuevo inquilino de Azure AD B2C.

  5. En Nombre de la organización y Nombre de dominio inicial, proporcione los valores correspondientes y, a continuación, seleccione Crear.

    Pantalla Crear inquilino de Azure AD B2C.

  6. Una vez completada la creación de Active Directory, seleccione la cuenta en la esquina superior derecha, seleccione Cambiar directorio y, a continuación, seleccione el directorio creado. Se le redirigirá a la nueva página principal del inquilino. Después, busque b2c y seleccione Azure AD B2C.

    Localice el servicio Azure AD B2C.

Adición de un registro de aplicación para la aplicación de Spring Boot

  1. En el panel Administrar, seleccione Registros de aplicaciones y, a continuación, seleccione Nuevo registro.

    Captura de pantalla de Azure Portal que muestra la pantalla Registros de aplicaciones de Azure AD B2C.

  2. En el campo Nombre, escriba el nombre de la aplicación y seleccione Registrar.

    Formulario para registrar una aplicación de Azure AD B2C.

  3. De nuevo en el panel Administrar, seleccione Registros de aplicaciones y, a continuación, seleccione el nombre de la aplicación que ha creado.

    Pantalla Registros de aplicaciones con el nombre para mostrar seleccionado.

  4. Seleccione Autenticación y, a continuación, Agregar una plataforma y, después, Web. Establezca los URI de redireccionamiento en http://localhost:8080/login/oauth2/code/ y, a continuación, seleccione Configurar.

    Opciones seleccionadas para la autenticación, agregar una plataforma, web.

    Pantalla Configurar Web con el campo URI de redirección seleccionado.

Adición de secretos de aplicación para la aplicación

Seleccione Certificados y secretos y, después, Nuevos secretos de cliente. Introduzca la descripción del secreto y, a continuación, seleccione Agregar. Después de crear el secreto, seleccione el icono de copia junto al valor del secreto para copiarlo y usarlo más adelante en este artículo.

Pantalla Agregar un secreto de cliente.

Pantalla Certificados y secretos con el botón Copiar seleccionado.

Nota:

Si deja la sección Certificados y secretos y vuelve, no podrá ver el valor del secreto. En ese caso, debe crear otro secreto y copiarlo para usarlo más adelante. Algunas veces, el valor del secreto generado puede contener caracteres que son problemáticos para su inclusión en el archivo application.yml, como la barra diagonal inversa o el acento grave. En ese caso, descarte ese secreto y genere otro.

Incorporación de flujo de usuario

  1. Vaya a la página principal del inquilino. En la sección Directivas del panel izquierdo, seleccione Flujos de usuario y, después, Nuevo flujo de usuario.

  2. Ahora dejará este tutorial, ejecutará otro tutorial y volverá a este tutorial cuando haya terminado. Estos son algunos aspectos que hay que tener en cuenta cuando visite el otro tutorial.

    • Comience en el paso que le pide que seleccione Nuevo flujo de usuario.
    • Cuando este tutorial haga referencia a webapp1, use en su lugar el valor que especificó para Grupo.
    • Al seleccionar las notificaciones que se van a devolver de los flujos, asegúrese de que se selecciona Nombre para mostrar. Sin esta notificación, la aplicación que se compila en este tutorial no funcionará.
    • Cuando se le pide que ejecute los flujos de usuario, la dirección URL de redireccionamiento que especificó anteriormente aún no está activa. Todavía puede ejecutar los flujos, pero el redireccionamiento no se completará correctamente. Se espera que esto sea así.
    • Cuando llegue a "Pasos siguientes", vuelva a este tutorial.

    Siga todos los pasos descritos en Tutorial: Creación de flujos de usuario en Azure Active Directory B2C para crear flujos de usuario para "registro e inicio de sesión", "edición de perfiles" y "restablecimiento de contraseña".

    Azure AD B2C admite cuentas locales, así como proveedores de identidades sociales. Para ver un ejemplo de cómo crear un proveedor de identidades de GitHub, consulte Configuración de la suscripción y del inicio de sesión con una cuenta de GitHub mediante Azure Active Directory B2C.

Configuración y compilación de la aplicación

Ahora que ha creado la instancia de Azure AD B2C y algunos flujos de usuario, conectará la aplicación de Spring a la instancia de Azure AD B2C.

  1. Desde la línea de comandos, vaya al directorio donde descomprimió el archivo ZIP que descargó de Spring Initializr.

  2. Vaya a la carpeta principal del proyecto y abra el archivo del proyecto de Maven pom.xml en un editor de texto.

  3. Agregue las dependencias para la seguridad OAuth2 de Spring a pom.xml:

    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory-b2c</artifactId>
        <version>See Below</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
        <version>See Below</version>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        <version>See Below</version>
    </dependency>
    

    Para spring-cloud-azure-starter-active-directory-b2c, actualice a la versión más reciente disponible. Es posible que pueda usar mvnrepository.com para consultarla.

    Para spring-boot-starter-thymeleaf, use la versión correspondiente a la versión de Spring Boot seleccionada anteriormente, por ejemplo 2.3.4.RELEASE.

    Para thymeleaf-extras-springsecurity5, use la versión más reciente disponible. Es posible que pueda usar mvnrepository.com para consultarla. En el momento de escribir este artículo, la versión más reciente es 3.0.4.RELEASE.

  4. Guarde y cierre el archivo pom.xml.

    • Para comprobar si las dependencias son correctas, ejecute mvn -DskipTests clean install. Si no ve BUILD SUCCESS, solucione y resuelva el problema antes de continuar.
  5. Vaya a la carpeta src/main/resources del proyecto y cree un archivo application.yml en un editor de texto.

  6. Especifique la configuración del registro de su aplicación con los valores que creó anteriormente; por ejemplo:

    spring:
      cloud:
        azure:
          active-directory:
            b2c:
              enabled: true
              base-uri: https://<your-tenant-initial-domain-name>.b2clogin.com/<your-tenant-initial-domain-name>.onmicrosoft.com/
              credential:
                client-id: <your-application-ID>
                client-secret: '<secret-value>'
              login-flow: sign-up-or-sign-in
              logout-success-url: <your-logout-success-URL>
              user-flows:
                sign-up-or-sign-in: <your-sign-up-or-sign-in-user-flow-name> 
                profile-edit: <your-profile-edit-user-flow-name> 
                password-reset: <your-password-reset-user-flow-name> 
              user-name-attribute-name: <your-user-name-attribute-name> 
    

    Observe que el valor client-secret está entre comillas simples. Esto es necesario porque el valor de <secret-value> seguramente contendrá algunos caracteres que tienen que estar entre comillas simples cuando están presentes en YAML.

    Nota:

    En el momento de escribir este artículo, la lista completa de valores de integración de Azure Directory Spring B2C que están disponibles para usar en application.yml es la siguiente:

    spring:
      cloud:
        azure:
          active-directory:
            b2c:
              enabled: true
              base-uri:
              credential:
                client-id:
                client-secret:
              login-flow:  
              logout-success-url:
              user-flows:
                sign-up-or-sign-in:
                profile-edit: # optional
                password-reset: # optional
              user-name-attribute-name:
    

    El archivo application.yml está disponible en spring-cloud-azure-starter-active-directory-b2c sample: aad-b2c-web-application en GitHub.

  7. Guarde y cierre el archivo application.yml.

  8. Cree una carpeta denominada controller en src/main/java/<yourGroupId>/<yourGroupId>, reemplazando por <yourGroupId> el valor especificado para Group.

  9. Cree un archivo de Java nuevo llamado WebController.java en la carpeta controller y ábralo en un editor de texto.

  10. Escriba el código siguiente, cambiando yourGroupId al valor que corresponda y, a continuación, guarde y cierre el archivo:

    package yourGroupId.yourGroupId.controller;
    
    import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
    import org.springframework.security.oauth2.core.user.OAuth2User;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class WebController {
    
        private void initializeModel(Model model, OAuth2AuthenticationToken token) {
            if (token != null) {
                final OAuth2User user = token.getPrincipal();
    
                model.addAttribute("grant_type", user.getAuthorities());
                model.addAllAttributes(user.getAttributes());
            }
        }
    
        @GetMapping(value = "/")
        public String index(Model model, OAuth2AuthenticationToken token) {
            initializeModel(model, token);
    
            return "home";
        }
    
        @GetMapping(value = "/greeting")
        public String greeting(Model model, OAuth2AuthenticationToken token) {
            initializeModel(model, token);
    
            return "greeting";
        }
    
        @GetMapping(value = "/home")
        public String home(Model model, OAuth2AuthenticationToken token) {
            initializeModel(model, token);
    
            return "home";
        }
    }
    

    Como todos los métodos del controlador llaman a initializeModel(), y ese método llama a model.addAllAttributes(user.getAttributes());, cualquier página HTML en src/main/resources/templates puede tener acceso a cualquiera de esos atributos, como ${name}, ${grant_type} o ${auth_time}. De hecho, los valores devueltos por user.getAttributes() son las notificaciones de id_token para la autenticación. La lista completa de notificaciones disponibles se muestra en Tokens de identificador de la plataforma de identidad de Microsoft.

  11. Cree una carpeta denominada security en src/main/java/<yourGroupId/<yourGroupId>>, reemplazando por yourGroupId el valor especificado para Group.

  12. Cree un archivo Java nuevo llamado WebSecurityConfiguration.java en la carpeta security y ábralo en un editor de texto.

  13. Escriba el código siguiente, cambiando yourGroupId al valor que corresponda y, a continuación, guarde y cierre el archivo:

    package yourGroupId.yourGroupId.security;
    
    import com.azure.spring.cloud.autoconfigure.aadb2c.AadB2cOidcLoginConfigurer;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @EnableWebSecurity
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        private final AadB2cOidcLoginConfigurer configurer;
    
        public WebSecurityConfiguration(AadB2cOidcLoginConfigurer configurer) {
            this.configurer = configurer;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .apply(configurer)
            ;
        }
    }
    
  14. Copie el archivo home.html del ejemplo spring-cloud-azure-starter-active-directory-b2c: aad-b2c-web-application en src/main/resources/templates y reemplace y ${your-profile-edit-user-flow}${your-password-reset-user-flow} por los nombres de los flujos de usuario que creó anteriormente.

Compilación y prueba de la aplicación

  1. Abra un símbolo del sistema y cambie el directorio a la carpeta donde se encuentra el archivo pom.xml de su aplicación.

  2. Compile la aplicación de Spring Boot con Maven y ejecútela; por ejemplo:

    Nota:

    Es muy importante que la hora según el reloj del sistema en el que se ejecuta la aplicación de Spring Boot local sea preciso. Hay muy poca tolerancia a la desviación del reloj cuando se usa OAuth 2.0. Incluso tres minutos de inexactitud pueden provocar un error en el inicio de sesión con un error similar a [invalid_id_token] An error occurred while attempting to decode the Jwt: Jwt used before 2020-05-19T18:52:10Z. En el momento de redactar este documento, time.gov indica la diferencia de su reloj respecto de la hora real. La aplicación se ejecutó correctamente con una desviación de +0,019 segundos.

    mvn -DskipTests clean package
    mvn -DskipTests spring-boot:run
    
  3. Después de que Maven compile e inicie la aplicación, abra http://localhost:8080/ en un explorador web; se le redirigirá a la página de inicio de sesión.

    Página de inicio de sesión de la aplicación web.

  4. Seleccione el vínculo que tenga el texto relacionado con el inicio de sesión. Se le redirigirá a Azure AD B2C para iniciar el proceso de autenticación.

  5. Una vez que haya iniciado sesión correctamente, debería ver el ejemplo home page desde el explorador.

    Inicio de sesión correcto de la aplicación web.

Solución de problemas

En las secciones siguientes se describe cómo resolver algunos problemas que pueden surgir.

Falta el nombre de los atributos

Al ejecutar el ejemplo, puede aparecer una excepción con el mensaje Missing attribute 'name' in attributes. El registro de esta excepción tendrá un aspecto similar al de la salida siguiente:

java.lang.IllegalArgumentException: Missing attribute 'name' in attributes
at org.springframework.security.oauth2.core.user.DefaultOAuth2User.<init>(DefaultOAuth2User.java:67) ~[spring-security-oauth2-core-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.<init>(DefaultOidcUser.java:89) ~[spring-security-oauth2-core-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService.loadUser(OidcUserService.java:144) ~[spring-security-oauth2-client-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService.loadUser(OidcUserService.java:63) ~[spring-security-oauth2-client-5.3.6.RELEASE.jar:5.3.6.RELEASE]

Si recibe este error, compruebe de nuevo el flujo de trabajo de usuario que creó en Tutorial: Creación de flujos de usuario en Azure Active Directory B2C. Cuando cree el flujo de trabajo de usuario, en Atributos y notificaciones de usuario, asegúrese de elegir atributos y notificaciones en Nombre para mostrar. Además, asegúrese de configurar correctamente user-name-attribute-name en el archivo application.yml.

Inicio de sesión con bucles en el punto de conexión de B2C

Este problema es más probable que se deba a cookies contaminadas de localhost. Limpie las cookies de localhost e inténtelo de nuevo.

Resumen

En este tutorial, ha creado una nueva aplicación web de Java mediante el iniciador de Azure Active Directory B2C, ha configurado un nuevo inquilino de Azure AD B2C y ha registrado una nueva aplicación en él; después, ha configurado la aplicación para que use las clases y anotaciones de Spring para proteger la aplicación web.

Limpieza de recursos

Cuando ya no lo necesite, use Azure Portal para eliminar los recursos creados en este artículo y evitar cargos inesperados.

Pasos siguientes

Para más información acerca de Spring y Azure, vaya al centro de documentación de Azure.