Non di fiducia certificato utilizzando ksoap2-Android
-
09-10-2019 - |
Domanda
sto usando ksoap2-Android per effettuare una chiamata al servizio WCF su SSL. Posso farlo funzionare senza SSL, ma ora voglio fare la chiamata su SSL, ma ho eseguito in alcuni problemi.
sto usando il HttpsTransportSE invece di HttpTransportSE, ma sto ottenendo l'errore: javax.net.ssl.SSLException: Non attendibile certificato server
Come posso risolvere questo problema?
Posso aggiungere il certificato del server al Keystore in Android per risolvere il problema?
private static final String SOAP_ACTION = "http://example.com/Service/GetInformation";
private static final String METHOD_NAME = "GetInformation";
private static final String NAMESPACE = "http://example.com";
private static final String URL = "dev.example.com/Service.svc";
public static Result GetInformation()
{
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
PropertyInfo property = new PropertyInfo();
property.name = "request";
Request request =
new Request("12", "13", "Ben");
userInformationProperty.setValue(request);
userInformationProperty.setType(request.getClass());
request.addProperty(property);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
envelope.addMapping(NAMESPACE, "Request",new Request().getClass());
HttpsTransportSE transport = new HttpsTransportSE(URL, 443, "", 1000);
//HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
transport.debug = true;
try
{
transport.call(SOAP_ACTION, envelope);
return Result.FromSoapResponse((SoapObject)envelope.getResponse());
}
catch (IOException e)
{
e.printStackTrace();
}
catch (XmlPullParserException e)
{
e.printStackTrace();
}
return null;
}
Soluzione
Beh, c'è un modo più semplice per fare questo invece di modificare HttpsServiceConnectionSE. È possibile installare un gestore di falso fiducia come descritto in http://groups.google.com/group/android-developers/browse_thread/thread/1ac2b851e07269ba/c7275f3b28ad8bbc?lnk=gst&q=certificate e quindi chiamare allowAllSSL () prima di fare qualsiasi comunicazione SSL / chiamata a ksoap2 . Si registrerà un nuovo HostnameVerifier predefinito e TrustManager. ksoap2, quando si fa la comunicazione SSL, utilizzerà quelli di default e funziona come un fascino.
Si può anche mettere un po 'più sforzo in questo, ne fanno (molto) più sicuro e installare i certificati in un'applicazione direttore di fiducia locale, immagino. Ero in una rete sicura e non ha paura di man-in-the-middle attacchi così ho appena fatto la prima.
L'ho trovato necessario usare KeepAliveHttpsTransportSE come questo new KeepAliveHttpsTransportSE(host, port, file, timeout);
. I parametri vanno in un oggetto URL, così ad esempio Per accedere a un'installazione Jira è qualcosa di simile new KeepAliveHttpsTransportSE("host.whatever", 443, "/rpc/soap/jirasoapservice-v2", 1000)
.
A volte è utile se siete nuovi alla tecnologia o il servizio web che si desidera utilizzare per giocare con essa in un ambiente J2SE, invece di nell'emulatore o anche sul dispositivo, ma nel J2SE / ME ksoap2 biblioteca (KeepAlive) HttpsTransportSE roba manca (io ho usato ksoap2-J2SE-full-2.1.2.jar). Che cosa si potrebbe fare è quello di ottenere i sorgenti per le tre classi HttpsTransportSE, KeepAliveHttpsTransportSE, e HttpsServiceConnectionSE dal Android spin-off ksoap2-android e metterli nel progetto J2SE e li usa. Ha funzionato per me e divenne un miglioramento della produttività per ottenere i primi passi a destra con uno sconosciuto e il servizio web abbastanza complesso.
Altri suggerimenti
Per completare la risposta di Vedran con un po 'di codice sorgente, mi dispiace non posso commentare.
Il TrustManager:
private static TrustManager[] trustManagers;
public static class _FakeX509TrustManager implements
javax.net.ssl.X509TrustManager {
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return (true);
}
public boolean isServerTrusted(X509Certificate[] chain) {
return (true);
}
public X509Certificate[] getAcceptedIssuers() {
return (_AcceptedIssuers);
}
}
public static void allowAllSSL() {
javax.net.ssl.HttpsURLConnection
.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
javax.net.ssl.SSLContext context = null;
if (trustManagers == null) {
trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() };
}
try {
context = javax.net.ssl.SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
Log.e("allowAllSSL", e.toString());
} catch (KeyManagementException e) {
Log.e("allowAllSSL", e.toString());
}
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context
.getSocketFactory());
}
La chiamata al tuo metodo:
allowAllSSL();
HttpsTransportSE httpsTransport = new HttpsTransportSE(Server,443, URL, 1000);
Note:
- Server è l'URL del server.
- 443 è la porta predefinita https, si devono ancora specificare una porta in quanto il costruttore si aspetta uno.
- URL il percorso per l'operazione WS
- 1000 ES il timeout
che è costruito come: [Https: // server: 443 / URL]
Opere per me WCF servizio KSOAP + Web con Eclipse
private static SoapObject getBody(final SoapSerializationEnvelope soapEnvelope) throws Exception {
if (soapEnvelope.bodyIn == null) {
throw new Exception("soapEnvelope.bodyIn=null");
}
else if (soapEnvelope.bodyIn.getClass() == SoapFault.class) {
throw new ExceptionLogic((SoapFault) soapEnvelope.bodyIn));
}
else {
return (SoapObject) soapEnvelope.bodyIn;
}
}
private static SoapSerializationEnvelope sendRequete(final SoapObject soapReq, final String classMappingName,
final Class<?> classMapping, final int timeOutSpecial) {
final SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
soapEnvelope.implicitTypes = true;
soapEnvelope.dotNet = true;
if (classMappingName != null) {
soapEnvelope.addMapping(NAMESPACE, classMappingName, classMapping);
}
soapEnvelope.setOutputSoapObject(soapReq);
try {
final HttpTransportSE httpTransport = new HttpTransportSE(Constante.urlWebService, timeOutSpecial);
httpTransport.debug = BuildConfig.DEBUG;
// Prod
if (Constante.urlWebService.startsWith("https://")) {
final List<HeaderProperty> headerList = new ArrayList<HeaderProperty>();
headerList.add(new HeaderProperty("Authorization", "Basic "
+ org.kobjects.base64.Base64.encode((Constante.CERTIFICAT_LOGIN + ":" + Constante.CERTIFICAT_MDP).getBytes())));
FakeX509TrustManager.allowAllSSL();
httpTransport.call(NAMESPACE + "/" + soapReq.getName(), soapEnvelope, headerList);
}
// Test
else {
httpTransport.call(NAMESPACE + "/" + soapReq.getName(), soapEnvelope);
}
return soapEnvelope;
}
catch (final Exception e) {
throw new Exception("Erreur : " + e.getMessage(), e);
}
}
private static class FakeX509TrustManager implements X509TrustManager {
private static TrustManager[] trustManagers;
private final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};
@Override
public X509Certificate[] getAcceptedIssuers() {
return _AcceptedIssuers;
}
public static void allowAllSSL() {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(final String hostname, final SSLSession session) {
return true;
}
});
SSLContext context = null;
if (trustManagers == null) {
trustManagers = new TrustManager[] { new FakeX509TrustManager() };
}
try {
context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
}
catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (final KeyManagementException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
}
@Override
public void checkClientTrusted(final X509Certificate[] arg0, final String arg1) throws CertificateException {
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
}
}
Si, probabilmente si può provare questo fuori
C'è stato un bug che è stato depositato l'issue tracker per quanto riguarda questo
http://code.google.com/p/android / temi / dettaglio? id = 2388