oidc - Spring Security y la migración de Google OpenID Connect
spring security oauth2 example mkyong (1)
Preguntas:
1) ¿Cuál es la mejor manera de integrar la autenticación de OpenID Connect en una aplicación web que utiliza Spring Security para la autenticación?
2) ¿Hay alguna manera, ya sea del lado MITREid o del lado de las Cuentas de Google, de hacer que el filtro de autenticación MITREid OpenID Connect funcione con el servicio OpenID Connect de Google?
Estoy seguro de que las respuestas a estas preguntas serán útiles para cualquier desarrollador que use el módulo Spring Security OpenID para autenticarse con Google.
Detalle:
Mi aplicación web utiliza el módulo OpenID de Spring Security ( <openid-login .../>
) para la autenticación con cuentas de Google como proveedor de identidad. es decir, los usuarios se autentican usando sus Google Apps o la dirección de correo electrónico de GMail.
Recientemente, cada vez que los usuarios se autentican, reciben este mensaje de advertencia de las cuentas de Google:
Aviso importante: OpenID2 para cuentas de Google se va a retirar el 20 de abril de 2015.
Por lo tanto, Google retira soporte para OpenID, lo apagará por completo en abril de 2015 y establece que debe cambiar al protocolo OpenID Connect si desea autenticarse con cuentas de Google.
Esperaba que Spring Security tuviera soporte integrado para OpenID Connect, del mismo modo que tiene soporte integrado para OpenID. por ejemplo, algo así como un elemento <openid-connect-login .../>
. Pero mis búsquedas no han encontrado tal apoyo.
El mejor candidato que he encontrado hasta ahora es MITREid Connect. Incluye un filtro de autenticación de Spring Security llamado OIDCAuthenticationFilter
para OpenID Connect. El problema es que no interopera con la implementación de OpenID Connect de Google.
Traté de clonar la aplicación web simple MITREid y la configuré para autenticar (usando OpenID Connect) con Cuentas de Google. Pero no funcionó porque depende de una versión que la implementación de OpenID Connect de Google no admite. El mensaje de error de las cuentas de Google fue:
Parámetro no permitido para este tipo de mensaje: nonce
Luego intenté conectar mi propia implementación de la interfaz AuthRequestUrlBuilder de AuthRequestUrlBuilder
en la configuración de MITREid. La única diferencia entre mi implementación y la implementación de MITREid fue que no envié el nonce.
El hecho de no enviar la implementación de OpenID Connect de Google hizo feliz, pero MITREid arrojó una excepción cuando no pudo encontrar un nonce en la respuesta de autenticación de Google. El mensaje de error fue:
Autenticación fallida: el token de ID no contenía un reclamo de nonce
Seguí la excepción MITREid hasta estas líneas en OIDCAuthenticationFilter de OIDCAuthenticationFilter
:
// compare the nonce to our stored claim
String nonce = idClaims.getStringClaim("nonce");
if (Strings.isNullOrEmpty(nonce)) {
logger.error("ID token did not contain a nonce claim.");
throw new AuthenticationServiceException("ID token did not contain a nonce claim.");
}
Pero no hay forma de que extienda la implementación de MITREid para ignorar el nonce. ¡Tan cerca, pero a la vez tan lejos! Si las cuentas de Google aceptaran el nonce o MITREid podría configurarse para ignorar el nonce entonces tendríamos una solución.
Dentro de la lista de problemas de MITREid Connect en github, he encontrado que otros se han encontrado con estos problemas similares:
1) # 726 - Documentación sobre el uso del cliente con Google como proveedor de autenticación
2) # 704 - Agregue un atributo useNonce en ServerConfiguration para indicar si el IdP acepta el valor nonce en sus solicitudes.
Así que estoy atascado. En abril de 2015, Google cerrará la autenticación de Open ID.
Algunos enlaces relevantes:
1) https://support.google.com/accounts/answer/6135882
2) https://www.tbray.org/ongoing/When/201x/2014/03/01/OpenID-Connect
3) https://github.com/mitreid-connect
4) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/blob/master/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java
5) https://github.com/mitreid-connect/simple-web-app
6) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/blob/master/openid-connect-client/src/main/java/org/mitre/openid/connect/client/service/impl/PlainAuthRequestUrlBuilder.java
7) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues/726
8) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/pull/704
2015-02-18 Actualización
La funcionalidad se ha agregado recientemente a la rama de desarrollo de mitreid-connect para deshabilitar el nonce, lo que hace feliz al servidor OIDC de Google. Afortunadamente, mitreid-connect también brindó orientación sobre la interoperación con Google . Desafortunadamente, el cambio de "no habilitado" aún no está disponible en Maven central, pero con suerte eso cambiará pronto.
AFAIK, no existe una migración limpia y fácil de Spring Security desde OpenID hasta la autenticación de OpenID Connect. La implementación de la autenticación OpenID con Spring Security es directa utilizando el bien documentado <openid-login/>
pero no existe un análogo para OpenID Connect.
La alternativa MITREid aún está en una rama de desarrollo y no está disponible en Maven Central y, por lo tanto, no es un candidato.
En los comentarios, Chuck Mah señala cómo implementar Openid connect y Spring Security, donde Romain F. proporciona el código de muestra .
El código de muestra de Romain me apuntó en la dirección correcta. Dado que el tiempo se está agotando, opté por el enfoque de romain, que consistía en escribir un Spring Security AuthenticationFilter personalizado que utiliza spring-security-oauth2 para consultar el punto final oauth2 api userinfo (para Google es https://www.googleapis.com/oauth2 / v2 / userinfo ). Se supone que si podemos consultar con éxito el punto final de la información del usuario, el usuario se habrá autenticado con éxito para que podamos confiar en la información devuelta, por ejemplo, la dirección de correo electrónico del usuario.
Cuando comencé a aprender sobre OpenID Connect, el " identificador de identificación " parecía ser el concepto central. Sin embargo, al buscar el código fuente spring-security-oauth2, parece que se ignora. Esto lleva a la pregunta, ¿cuál es el punto del token de ID si podemos autenticar sin él (simplemente preguntando al punto de acceso oauth2 userinfo)?
Una solución minimalista, que preferiría, simplemente devolvería un token de ID validado. No habría necesidad de consultar el punto final de la información del usuario. Pero no existe tal solución en la forma de un filtro de autenticación Spring Security.
Mi aplicación web no era una aplicación de arranque de primavera como la de Romain. spring-boot hace mucha configuración detrás de escena. Estos son algunos de los problemas / soluciones que encontré en el camino:
Problema: Estado HTTP 403: token CSRF esperado no encontrado. Ha expirado su sesión?
- solución: configuración java: httpSecurity.csrf (). disable ()
problema: HTTP Status 500 - Error al crear bean con el nombre ''scopedTarget.googleOAuth2RestTemplate'': la ''sesión'' del alcance no está activa para el hilo actual;
- solución: java config: OAuth2RestTemplate no necesita tener una sesión de ámbito (OAuth2ClientContext ya tiene una sesión de ámbito y eso es todo lo que necesita)
problema: HTTP Status 500 - Error al crear bean con el nombre ''scopedTarget.oauth2ClientContext'': la ''sesión'' del alcance no está activa para el hilo actual;
- solución: web.xml: agregar RequestContextListener
- explicación: porque se accede al bean con ámbito de sesión oauth2ClientContext fuera del alcance del Spring MVC DispatcherServlet (se está accediendo desde OpenIdConnectAuthenticationFilter, que es parte de la cadena de filtros de Spring Security).
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
problema: org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: se requiere una redirección para obtener la aprobación de los usuarios.
- solución: web.xml: Agregar definición de filtro de forma inmediata PRECEDENTE springSecurityFilterChain
<filter> <filter-name>oauth2ClientContextFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>oauth2ClientContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Desafortunadamente, OpenID Connect no nos permite solicitar solo alcance de email
. Cuando nuestros usuarios se autenticaron con OpenID, verían una pantalla de consentimiento como "webapp desea ver su dirección de correo electrónico" con la que se sentían cómodos. Ahora debemos solicitar los alcances del openid email
da como resultado una pantalla de consentimiento solicitando al usuario que comparta su perfil público completo con nosotros ... que realmente no necesitamos o no queremos ... y los usuarios se sienten menos cómodos con esta pantalla de consentimiento.