Italian [B4J] Collegarsi a Webservice con certificati Self-Signed

Teech

Member
Licensed User
Longtime User
Buongiorno a tutti.
Premetto che non sono per nulla esperto di questo genere di comunicazioni, ma sto provando a connettermi ad un WebService messo a disposizione da un software a cui collegarmi.

Sono partito da un esempio che mi hanno fornito in JS ma ancora non riesco a collegarmi, e mi viene restituito il seguente errore:
Waiting for debugger to connect...
Program started.
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:1946)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1640)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:242)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:200)
at okhttp3.internal.connection.RealConnection.buildConnection(RealConnection.java:174)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:114)
at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:196)
at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:132)
at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:101)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
at okhttp3.RealCall.execute(RealCall.java:63)
at anywheresoftware.b4h.okhttp.OkHttpClientWrapper.executeWithTimeout(OkHttpClientWrapper.java:156)
at anywheresoftware.b4h.okhttp.OkHttpClientWrapper.access$0(OkHttpClientWrapper.java:153)
at anywheresoftware.b4h.okhttp.OkHttpClientWrapper$ExecuteHelper.run(OkHttpClientWrapper.java:201)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: 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.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
at sun.security.validator.Validator.validate(Validator.java:262)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1622)
... 35 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
... 41 more
ResponseError. Reason: 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, Response:
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
Mi pare di capire che il problema sia sul fatto che il client (cioè la mia procedura) non accetta i certificati Self-Signedm necessari all'utilizzo del Webservice a cui mi sto connettendo.
Ho provato ad inserire il valore HU2_PUBLIC nei "Conditional Symbol" delle impostazioni di compilazione, ma senza risultati utili.
Il codice che utilizzo è il seguente:
B4X:
    Dim su As StringUtils
    Dim url As String="https://mioindirizzo/webservice"
    Dim dom As String=""
    Dim usr As String=su.EncodeBase64("CREDENZIALI".GetBytes("UTF8"))
    Dim aut As String=$"Auth"$
    If dom.Length>0 Then aut=$"${aut} Dominio ${dom}"$
    Dim j As HttpJob
    j.Initialize("",Me )
    j.PostString(url,usr)
    Wait For(j) JobDone(j As HttpJob)
    If j.Success Then
        Log(j.GetString)
    Else
        Log(j.ErrorMessage)
    End If
    j.GetRequest.SetHeader("Authorization",aut)
    j.GetRequest.SetContentType("application/json")
    j.Release

Potete darmi una indicazione su come procedere? Grazie
 

drgottjr

Expert
Licensed User
Longtime User
devi mostrare essatamente come hai fatto l'autorizzazione. qualcosa non quadra. e devi mettere i set-headers nel luoco giusto, no dopo la richiesta
 

Attachments

  • teech.png
    teech.png
    69.3 KB · Views: 157

Teech

Member
Licensed User
Longtime User
Per gli headers hai perfettamente ragione, li avevo spostati come test (per verificare se l'errore cambiava) e li ho postati erroneamente posizionati: anche mettendoli nella giusta sequenza l'errore non cambia.
La stringa per l'autorizzazione è una costante: il dominio viene richiesto quando ci si deve connettere all'installazione in cloud (non è il mio caso attualmente per cui il dominio è vuoto). Penso sia questo passaggio che non quadra, ma è quanto mi richiedono i produttori del gestionale.

Per completezza allego l'esempio che il produttore del WS mi ha mandato in JS:
JavaScript:
    var url = "https://mioindirizzo/webservice";
    var dom = "";
    var cr = "CREDENZIALI";  
    var cr64 = btoa(cr);
    var auth = "Auth "+cr64+" Dominio="+dom;  
    var req = new XMLHttpRequest();  
    req.onreadystatechange = function() {
        if (this.readyState === 4 && this.status === 200) {
            console.log(req.responseText);  
            alert('err')
        }else{
            console.log(req);
        }
    };  
    req.open("POST", url, true);  
    req.setRequestHeader('Authorization',auth);
    req.setRequestHeader('Content-Type','application/json; charset=utf-8');
Penso che il problema sia riscontrabile nel messaggio:
ResponseError. Reason: 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, Response:
Il produttore del WS mi dice che è necessario far accettare l'accesdso con certificati Self-Signed: vorrei provare a far accettare certificati self-signed a B4J, ma non trovo indicazioni su come verificare questa modalità.
 

LucaMs

Expert
Licensed User
Longtime User
Il produttore del WS mi dice che è necessario far accettare l'accesdso con certificati Self-Signed: vorrei provare a far accettare certificati self-signed a B4J, ma non trovo indicazioni su come verificare questa modalità.
You are looking for client certificates. It is not supported by jOkHttp.

Con i websocket è possibile aggirare la cosa, facendo accettare al client qualunque certificato. Vediamo se esista altrettanto con OKHttp...
 

Teech

Member
Licensed User
Longtime User
EDIT 10/08/2023 - sempre per completezze di informazione, usando HttpJob si può usare nel menu Build Configuration, inserire nel campo Conditional Symbols il valore HU2_ACCEPTALL
------
Usando OkHttpClient al posto di HttpJob per utilizzare l'inizializzazione con AcceptAll, funziona.
Ammetto di aver visto sul forum la OkHttpClient.InizializeAcceptAll, ma non capivo la differenza fra HttpJob e OkHttpClient, per cui non volevo incastrarmi un un ulteriore problema: provando invece funziona divinamente. A volte intestardirsi non paga ;)
Grazie mille.

Allego codice risolutivo, per completezza:
B4X:
Sub Process_Globals
    Private c As OkHttpClient
End Sub

Sub Button1_Click
    Dim su As StringUtils
    Dim url As String="https://mioindirizzo/webservice"
    Dim usr As String=su.EncodeBase64("CREDENZIALI".GetBytes("UTF8"))
    Dim dom As String=""
    Dim aut As String=$"Auth ${usr}"$
    If dom.Length>0 Then aut=$"${aut} Dominio ${dom}"$
    c.InitializeAcceptAll("client")

    Dim rq As OkHttpRequest
    rq.InitializePost2(url,usr.GetBytes("UTF8"))
    rq.SetContentType("application/json")
    rq.SetHeader("Authorization",aut)
    c.Execute(rq,0)
End Sub

Private Sub client_ResponseError (Response As OkHttpResponse, Reason As String, StatusCode As Int, TaskId As Int)
    Log($"Error: ${StatusCode}
          ${Response.ErrorResponse}"$)
End Sub

Private Sub client_ResponseSuccess (Response As OkHttpResponse, TaskId As Int)
    Log($"Response: ${Response.GetHeaders}"$)
End Sub
 
Last edited:
Top