Shinyproxy: Erreur de délai d'attente d'authentification SAML (?)

Créé le 15 févr. 2021  ·  6Commentaires  ·  Source: openanalytics/shinyproxy

Rebonjour! Au fur et à mesure que nous progressons dans le développement de notre application à l'aide de SAML, nous avons trouvé un problème d'authentification qui ne semble se produire que si un onglet est laissé ouvert pendant un certain temps (nous n'avons pas déterminé la durée exacte à l'origine du problème) et un utilisateur actualise ensuite son onglet (je ne sais pas si une nouvelle fenêtre le déclenche également à ce stade). Il semble qu'après cette période d'inactivité, ShinyProxy essaie de se réauthentifier et échoue pour une raison quelconque. La seule solution que j'ai trouvée est d'effacer les données du site dans le navigateur pour notre IdP (auth.company.com). Une fois cela fait, les choses fonctionnent comme prévu.

Lorsque cela se produit, ShinyProxy essaie de s'authentifier plusieurs fois de suite (je peux voir de nombreux rappels de redirection SAML défiler dans la barre d'URL), mais échoue finalement et me jette sur http://my.company.com/app/saml /SSO avec l'erreur suivante :

image

Dans les journaux du serveur, je vois ce qui suit :

shinyproxy-server_1  | 2021-02-15 04:00:11.531  INFO 1 --- [  XNIO-1 task-4] o.s.security.saml.log.SAMLDefaultLogger  : AuthNRequest;SUCCESS;XXX.XX.XX.XXX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;
shinyproxy-server_1  | 2021-02-15 04:00:11.608  INFO 1 --- [  XNIO-1 task-4] colMessageXMLSignatureSecurityPolicyRule : Validation of protocol message signature succeeded, message type: {urn:oasis:names:tc:SAML:2.0:protocol}Response
shinyproxy-server_1  | 2021-02-15 04:00:11.609  INFO 1 --- [  XNIO-1 task-4] o.s.security.saml.log.SAMLDefaultLogger  : AuthNResponse;FAILURE;XXX.XX.XX.XXX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;org.springframework.security.saml.SAMLStatusException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null

Quelque chose d'étrange est qu'il semble que la première tentative d'authentification réussisse, mais ShinyProxy ne l'aime pas pour une raison quelconque et essaie à nouveau.


Traçage complet de l'erreur :

~shinyproxy-server_1 |
sur org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:88)shinyproxy-server_1 |
sur org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:219)shinyproxy-server_1 |
at sun.reflect.GeneratedMethodAccessor63.invoke(Source inconnue)shinyproxy-server_1 |
à java.lang.reflect.Method.invoke(Method.java:498)shinyproxy-server_1 |
sur org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205)shinyproxy-server_1 |
sur org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:92)shinyproxy-server_1 |
sur org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)shinyproxy-server_1 |
sur org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)shinyproxy-server_1 |
sur org.springframework.security.web.authentication.
à org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)shinyproxy-server_1 |
sur org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)shinyproxy-server_1 |
sur org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)shinyproxy-server_1 |
sur org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)shinyproxy-server_1 |
sur org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)shinyproxy-server_1 |
sur org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)shinyproxy-server_1 |
sur org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)shinyproxy-server_1 |
sur org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)shinyproxy-server_1 |
à org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)shinyproxy-server_1 |
sur org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87)shinyproxy-server_1 |
sur org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)shinyproxy-server_1 |
sur org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)shinyproxy-server_1 |
sur io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)shinyproxy-server_1 |
sur org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)shinyproxy-server_1 |
à io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)shinyproxy-server_1 |
sur org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)shinyproxy-server_1 |
sur io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)shinyproxy-server_1 |
sur org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)shinyproxy-server_1 |
sur io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)shinyproxy-server_1 |
à io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)shinyproxy-server_1 |
à io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)shinyproxy-server_1 |
à io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:91)shinyproxy-server_1 |
à io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)shinyproxy-server_1 |
à io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)shinyproxy-server_1 |
à io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)shinyproxy-server_1 |
à io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)shinyproxy-server_1 |
à io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)shinyproxy-server_1 |
à io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)shinyproxy-server_1 |
à io.undertow.servlet.handlers.ServletInitialHandler.access 100$(ServletInitialHandler.java:78)shinyproxy-server_1 |
à io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)shinyproxy-server_1 |
à io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)shinyproxy-server_1 |
à io.undertow.servlet.handlers.ServletInitialHandler.access $ 000 (ServletInitialHandler.java:78)shinyproxy-server_1 |
à io.undertow.server.Connectors.executeRootHandler(Connectors.java:370)shinyproxy-server_1 |
sur org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)shinyproxy-server_1 |
sur org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)shinyproxy-server_1 |
à java.lang.Thread.run(Thread.java:748)~

La solution simple serait de cliquer sur le bouton "Déconnexion", mais ce bouton n'est pas affiché sur l'écran d'erreur SAML. C'est difficile à déboguer, car je ne peux pas le faire à la demande. Selon mon support IdP, ADFS émet en effet un jeton valide au début de ce processus, il semble donc qu'il s'agisse d'un problème local lié à la façon dont ShinyProxy gère le jeton qu'il reçoit. Je suppose que puisque l'onglet du navigateur ne s'est jamais fermé, le cookie de connexion a peut-être expiré et n'est pas renouvelé correctement, mais je n'ai aucune idée de ce dont je parle, alors prenez cela avec un grain de sel.

Je reviendrai avec des informations, espérons-le, plus utiles lorsque l'erreur se reproduira, mais j'étais curieux de voir si quelqu'un avait vu cela et avait des idées sur la façon de le corriger?

question

Tous les 6 commentaires

J'ai trouvé le problème suivant, qui pointe vers des messages d'erreur similaires indiquant une incompatibilité entre les algorithmes de signature SHA-1 et SHA-256, mais si tel était le cas dans notre installation, je ne sais pas pourquoi cela fonctionnerait la plupart du temps, mais échoue ensuite par intermittence après une longue période d'inactivité, donc je ne pense pas que ce soit mon problème.

En guise de suivi, j'ai défini la partie SAML de l'application sur la journalisation de niveau DEBUG , et j'ai vu ce qui suit à partir de l'un de ces événements de délai d'attente :

shinyproxy-server_1  | 2021-02-15 21:03:14.050 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.context.SAMLContextProviderImpl  : No IDP specified, using default http://auth.company.com/adfs/services/trust
shinyproxy-server_1  | 2021-02-15 21:03:14.050 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.util.SAMLUtil          : Index for AssertionConsumerService not specified, returning default
shinyproxy-server_1  | 2021-02-15 21:03:14.051 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLEntryPoint         : Processing SSO using WebSSO profile
shinyproxy-server_1  | 2021-02-15 21:03:14.051 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.websso.WebSSOProfileImpl      : Using default consumer service with binding urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
shinyproxy-server_1  | 2021-02-15 21:03:14.052 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.storage.HttpSessionStorage    : Storing message a17g5ahbxxxxxxxxxxx454jj to session hxxxxxxJ_E8xxxxxxxxHP_TwIxxxxxxxH
shinyproxy-server_1  | 2021-02-15 21:03:14.053  INFO 1 --- [  XNIO-1 task-2] o.s.security.saml.log.SAMLDefaultLogger  : AuthNRequest;SUCCESS;XXX.XX.XXX.XX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;
shinyproxy-server_1  | 2021-02-15 21:03:14.805 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Request is to process authentication
shinyproxy-server_1  | 2021-02-15 21:03:14.806 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Attempting SAML2 authentication using profile urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser
shinyproxy-server_1  | 2021-02-15 21:03:14.811 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.processor.SAMLProcessorImpl   : Retrieving message using binding urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
shinyproxy-server_1  | 2021-02-15 21:03:14.816  INFO 1 --- [  XNIO-1 task-2] colMessageXMLSignatureSecurityPolicyRule : SAML protocol message was not signed, skipping XML signature processing
shinyproxy-server_1  | 2021-02-15 21:03:14.816 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.util.SAMLUtil          : Found endpoint org.opensaml.saml2.metadata.impl.AssertionConsumerServiceImpl<strong i="7">@6531c789</strong> for request URL https://my.company.com/app/saml/SSO based on location attribute in metadata
shinyproxy-server_1  | 2021-02-15 21:03:14.816 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.storage.HttpSessionStorage    : Message a17g5ahb0gieeh9b4e48ff6a3d454jj found in session hXmYJ_E8wf6F2plFsHP_TwIZS1Cg6n2Vu4wD4i2H, clearing
shinyproxy-server_1  | 2021-02-15 21:03:14.817 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Verifying issuer of the Response
shinyproxy-server_1  | 2021-02-15 21:03:14.817 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Verifying signature
shinyproxy-server_1  | 2021-02-15 21:03:14.820 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.t.MetadataCredentialResolver     : Added 1 credentials resolved from metadata of entity http://auth.company.com/adfs/services/trust
shinyproxy-server_1  | 2021-02-15 21:03:14.826 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Processing Bearer subject confirmation
shinyproxy-server_1  | 2021-02-15 21:03:14.836 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Validation of authentication statement in assertion failed, skipping
shinyproxy-server_1  | org.springframework.security.authentication.CredentialsExpiredException: Authentication statement is too old to be used with value 2021-02-15T15:51:35.161Z
                        ...
shinyproxy-server_1  | 2021-02-15 21:03:14.839 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.SAMLAuthenticationProvider    : Error validating SAML message
shinyproxy-server_1  |
shinyproxy-server_1  | org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.841  INFO 1 --- [  XNIO-1 task-2] o.s.security.saml.log.SAMLDefaultLogger  : AuthNResponse;FAILURE;XXX.XX.XXX.XX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
shinyproxy-server_1  |  at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:265)
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.842  INFO 1 --- [  XNIO-1 task-2] e.o.containerproxy.service.UserService   : Authentication failure [user: ] [error: Error validating SAML message]
shinyproxy-server_1  | 2021-02-15 21:03:14.848 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
shinyproxy-server_1  |
shinyproxy-server_1  | org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.849 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Updated SecurityContextHolder to contain null Authentication
shinyproxy-server_1  | 2021-02-15 21:03:14.849 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler<strong i="8">@19dec0b4</strong>
shinyproxy-server_1  | 2021-02-15 21:03:14.858 ERROR 1 --- [  XNIO-1 task-2] org.thymeleaf.TemplateEngine             : [THYMELEAF][XNIO-1 task-2] Exception processing template "/": Error resolving template [/], template might not exist or might not be accessible by any of the configured Template Resolvers
shinyproxy-server_1  | org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/], template might not exist or might not be accessible by any of the configured Template Resolvers
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.861 ERROR 1 --- [  XNIO-1 task-2] io.undertow.request                      : UT005023: Exception handling request to /app/error
shinyproxy-server_1  |
shinyproxy-server_1  | org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/], template might not exist or might not be accessible by any of the configured Template Resolvers

Cette séquence est répétée 7 fois en 2 secondes environ avant que ShinyProxy n'abandonne et me renvoie à une page d'erreur générique de springboot, comme indiqué ci-dessus. Deux curiosités :

1) org.springframework.security.authentication.CredentialsExpiredException: Authentication statement is too old to be used with value 2021-02-15T15:51:35.161Z -- cela semble être la racine du problème, mais je ne sais pas s'il s'agit d'un problème du côté IdP ou du côté ShinyProxy

2) 2021-02-15 21:03:14.861 ERROR 1 --- [ XNIO-1 task-2] io.undertow.request : UT005023: Exception handling request to /app/error -- il semble que mon modèle d'erreur ne se charge pas correctement. Si c'était le cas, je pense que je pourrais mettre un lien vers la page "déconnexion", sur laquelle les utilisateurs pourraient cliquer pour réinitialiser leur session (je ne sais pas si cela fonctionnerait, juste une intuition)

Des idées?

Liens connexes:

1) https://stackoverflow.com/questions/48289763/spring-security-infinite-loop-after-initial-login-and-timeout
2) https://stackoverflow.com/questions/30528636/idp-initiated-saml-login-error-authentication-statement-is-too-old-to-be-used

Le lien 2 suggère quelques solutions : (1) aligner maxAuthenticationAge sur la durée de vie de l'ADFS ou (2) définir forceAuthN sur true

Est-ce possible à partir de la configuration ShinyProxy, ou est-ce que je cherche une version personnalisée nécessaire pour cela ?

Salut @jat255

Merci pour votre rapport et vos recherches approfondis! C'est tout à fait une coïncidence : j'ai également rencontré exactement le même problème sur l'un de nos déploiements. Hier j'ai trouvé les mêmes solutions que toi, je n'avais qu'à la tester :)

La définition de l'option forceAuthN résout en effet le problème de notre côté. Le seul inconvénient est que l'utilisateur est obligé de fournir à nouveau ses informations d'identification complètes, alors qu'ADFS estime que les informations d'identification de l'utilisateur sont toujours « assez récentes ». De plus, d'après le lien que vous avez fourni, il semble que certains IDP ignorent cette option (par exemple, Google). Vous pouvez activer le forceAuthN en le spécifiant dans votre configuration saml :

proxy:
  saml:
    idp-metadata-url: ... 
    ....
    force-authn: true

Cette option n'est pas encore documentée sur notre site, je m'en occupe.

La spécification de l'option maxAuthenticationAge n'est pas encore implémentée dans ShinyProxy. Cependant, comme je vois de la valeur dans cette option (par exemple, en utilisant google comme IDP), je vais implémenter une option pour cela.

Je vais également essayer de fournir un comportement plus utile en cas de CredentialsExpiredException .

@LEDfan merci beaucoup pour votre réponse rapide et votre solution ! J'ai implémenté ce changement, mais maintenant je dois attendre 24 heures pour voir si cela a fonctionné :smirk: J'ai au moins confirmé que je vois ForceAuthn="true" dans la charge utile SAML, donc l'option fonctionne définitivement sur le ShinyProxy côté.

Je pense que l'option forceAuthN ne sera pas trop difficile pour nos utilisateurs, car la plupart de nos utilisateurs utilisent l'authentification d'entreprise connectée à la gestion automatique des informations d'identification Windows, de sorte qu'ils n'ont pas à saisir de mot de passe pour accéder à Ressources protégées par SAML. Je ferai un rapport ici dans quelques jours pour vous faire savoir si cela a fonctionné pour notre cas.

Cela semble fonctionner au cours des derniers jours (je n'ai pas revu l'erreur), alors je vais continuer et clore cela. Merci encore!

Cette page vous a été utile?
0 / 5 - 0 notes