SAS Web Application Server et l’erreur « unable to find valid certification path to requested target »
Si vous utilisez une connexion chiffrée TLS/SSL avec SAS Web Server vous pouvez être confronté à une erreur SSLHandshakeException, lorsqu’une fois connecté (via SASLogin), vous tentez d’accéder à une application web SAS (par exemple SASStudio) :
Une fois ajouté dans le keystore, vous pouvez valider sa bonne prise en compte en utilisant l’outil
SAS TLS/SSL Diagnostic Tool ou l’outil InstallCert.
Si tout est ok, adieu ce vilain message d'erreur !
Et je vous offre aussi la stack java complète obtenue lors de l'apparition de cette erreur (fichier log dans LevX\Web\Logs\SASServer1_1)
Sources :
Préserver TLS et les personnalisations de proxy inversé existant (En front-end de SAS)
Configuration manuelle du serveur Web SAS pour HTTPS ( Utilisation de TLS avec les applications Web SAS et Reconfiguration pour utiliser HTTPS)
Chiffrement (Cryptage) dans SAS 9.4 : L'idéal pour tout comprendre. Si vous vous lancez dans une passage en HTTPS de votre plate-forme SAS, ne passez pas à côté de cette documentation !
Avant de vous lancer
Les processus de sécurité et de certification peuvent être très techniques. Vous ne devez exécuter aucune des tâches décrites cs sans une bonne compréhension des procédures de sécurité. Des modifications inappropriées peuvent avoir des effets extrêmement nocifs sur non seulement votre logiciel SAS, mais tous les logiciels que vous utilisez.Pourquoi cette erreur ?
Il s'agit d'une erreur la plus courante lors de l’implémentation de TLS/SSL (https) dans un environnement SAS de type Office Analytics ou Visual Analytics. Heureusement, il s'agit d'un problème facile à résoudre ! Cette erreur se produit lorsque le magasin de certificat de la JVM (keystore) utilisée par SAS Web Application Server n’a pas le certificat ayant signé le certificat du SAS Web Server.Quelques explications pour comprendre
Pour bien comprendre l’origine de cette erreur, il faut comprendre le fonctionnement SSL Une fois connecté via SASLogon, SAS Web Application Server tente d’établir une connexion avec le SAS Web Server : Comme cette communication se fait dans un contexte sécurisé, le SAS Web Application Server doit valider l’authentification du certificat sur Web Server. Alors, le SAS Web Application Server étudie le certificat du SAS Web Server. Pour faire simple, il va regarder qui a signé le certificat du SAS Web Server. Comme vous le savez, c’est le rôle de CA (Certificate authority) : Dans notre exemple le certificat du SAS Web Server a été signé « Nicolas Housset CA » : Une autorité de certification que j’ai créée, que seul moi utilise et que personne ne connait : Maintenant, SAS Web Application Server regarde s’il connait cette autorité. Comme je viens de vous le dire, c’est autorité est une autorité maison, il y a donc peu de chance que SAS Web Application Server connaisse son existence. Pour effectuer cette validation, SAS Web Application Server, va rechercher l’autorité « Nicolas Housset CA » dans son magasin de certificat (keystore). SAS Web Application Server étant une application JAVA exécuté par la JVM SAS, ce certificat d’autorité doit se trouver dans le magasin jssecacerts : « Nicolas Housset CA » n’est donc pas présent au milieu des certificat RapidSSL,AlphaSSL,GeoTrust,GlobalSign ou Symantec. SAS Web Application Server ne peut donc pas valider sa connexion avec le SAS Web Server et remonte l’erreur : « unable to find valid certification path to requested target » Il faut donc ajouter cette autorité dans le keystore jssecacerts : L’ajout dans le keystore SAS se fait via une commande keytool :
1 |
Keytool -import -trustcacerts -keystore \SASHome\SASPrivateJavaRuntimeEnvironment\9.4\jre\lib\security\jssecacert -alias nicolashousset -file "nicolas-housset-CA.crt" |
Gérer le bundle CA avec SAS Deployment Manager
À partir de SAS 9.4 (TS1M3 Rev. 940_15w29), il est possible d’utiliser SAS Deployment Manager pour ajouter vos certificats CA. Les bundles CA approuvés fournis avec SAS sont dans des formats multiples, pour une utilisation dans différents contextes SAS Client SSL. Aussi , en utilisant SAS Deployment Manager vos certificats sont ajoutés aux fichiers trustedcerts.pem et trustedcerts.jks. Le fichier trustedcerts.jks est également copié dans le fichier jssecacerts de la JRE privée SAS. Après avoir ajouté des fichiers à l'aide de SAS Deployment Manager, les trois fichiers contiennent les certificats CA redistribués par SAS à partir de Mozilla ainsi que les certificats que vous venez d'ajouter. Le bundle CA que SAS redistribue provient de Mozilla et la liste des CA racines est disponible : https://wiki.mozilla.org/CA:IncludedCACadeau bonux !
La vidéo complète de mes explications :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
2016-11-26 13:04:23,401 [tomcat-http--30] ERROR [unknown] org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/SASStudio].[coderServlet] - "Servlet.service()" pour la servlet coderServlet a généré une exception java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.sas.svcs.security.authentication.validation.jasig.HttpClientResponseRetriever.getResponseFromServer(HttpClientResponseRetriever.java:113) at com.sas.svcs.security.authentication.validation.jasig.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:44) at org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:187) at com.sas.svcs.security.authentication.validation.ServiceTicketValidator.validate(ServiceTicketValidator.java:79) at org.springframework.security.cas.authentication.CasAuthenticationProvider.authenticateNow(CasAuthenticationProvider.java:140) at org.springframework.security.cas.authentication.CasAuthenticationProvider.authenticate(CasAuthenticationProvider.java:126) at com.sas.svcs.security.authentication.provider.AuthenticationProvider.authenticate(AuthenticationProvider.java:85) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) at org.springframework.security.cas.web.CasAuthenticationFilter.attemptAuthentication(CasAuthenticationFilter.java:242) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:194) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) at com.sas.svcs.security.authentication.session.jasig.SingleSignOutFilter.doFilterInternal(SingleSignOutFilter.java:60) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) at com.sas.svcs.security.authentication.web.filters.RevokableTokenLogoutFilter.doFilter(RevokableTokenLogoutFilter.java:38) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) at com.sas.svcs.security.authentication.web.filters.CsrfRefererCheckerFilter.doFilterInternal(CsrfRefererCheckerFilter.java:909) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) at com.sas.framework.webapp.servlet.ApplicationNameFilter.onDoFilter(ApplicationNameFilter.java:55) at com.sas.framework.webapp.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at com.sas.servlet.filters.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:62) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at com.sas.framework.webapp.servlet.SanitizingRequestFilter.onDoFilter(SanitizingRequestFilter.java:101) at com.sas.framework.webapp.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1916) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:279) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:273) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1472) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:213) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:913) at sun.security.ssl.Handshaker.process_record(Handshaker.java:849) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1035) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1344) at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:721) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828) at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116) at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096) at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398) at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323) at com.sas.svcs.security.authentication.validation.jasig.HttpClientResponseRetriever.getResponseFromServer(HttpClientResponseRetriever.java:109) ... 57 more |