Es kann sein, dass ich hier jetzt bisschen was falsches dazu erzähle, aber es war auch schon, wie gesagt, lange her, dass ich das gemacht habe
Also, da der DefaultHTTPClient nicht mit HTTPS umgehen konnte, hab ich eine neue Klasse erstellt, die von DefaultHTTPClient ableitet und so implementiert, dass dieser auch mit HTTPS klar kommt.
SecureHTTPClient:
public class SecureHttpClient extends DefaultHttpClient
{
final Context context;
public SecureHttpClient(Context c)
{
context = c;
}
@Override
protected ClientConnectionManager createClientConnectionManager()
{
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
try
{
registry.register(new Scheme("https", newSslSocketFactory(), 443));
}
catch (KeyManagementException e)
{
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (KeyStoreException e)
{
e.printStackTrace();
}
catch (UnrecoverableKeyException e)
{
e.printStackTrace();
}
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException
{
KeyStore trusted = null;
try
{
trusted = new KeyStoreHandler(context).getKeyStoreStream();
}
catch (Exception e)
{
e.printStackTrace();
}
return new SSLSocketFactory(trusted);
}
}
Alles anzeigen
In der newSslSocketFactory() wird dann der KeyStore geladen, welches von der KeyStoreHandler Klasse gemacht wird.
KeyStoreHandler:
public class KeyStoreHandler
{
private static final String KEYSTORE_FILE_NAME = "keystore.bks";
private static final char[] KEYSTORE_PASSWORD = "passwort".toCharArray();
private static final String CERTIFICATE_ALIAS = "alias";
private static final String CERTIFICATE_URL = "cert.url";
private static final int KEYSTORE_NOT_EXIST = 0;
private static final int KEYSTORE_EXIST = 1;
private Context context;
private KeyStore keyStore;
public KeyStoreHandler(Context c)
{
context = c;
}
private Certificate downloadCertificate(String url) throws Exception
{
URL certUrl = new URL(url);
HttpURLConnection con = (HttpURLConnection) certUrl.openConnection();
con.connect();
Certificate cert = null;
int responseCode = con.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK)
{
InputStream is = con.getInputStream();
CertificateFactory certF = CertificateFactory.getInstance("X.509");
cert = certF.generateCertificate(is);
}
return cert;
}
private int checkKeyStore()
{
int ret;
File keyStoreFile = context.getFileStreamPath(KEYSTORE_FILE_NAME);
if(keyStoreFile.exists())
{
ret = KEYSTORE_EXIST;
}
else
{
ret = KEYSTORE_NOT_EXIST;
}
return ret;
}
public KeyStore getKeyStoreStream() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException
{
InputStream in;
keyStore = KeyStore.getInstance("BKS");
if(checkKeyStore() == KEYSTORE_NOT_EXIST)
{
createNewKeyStore();
}
in = context.openFileInput(KEYSTORE_FILE_NAME);
keyStore.load(in, KEYSTORE_PASSWORD);
return keyStore;
}
private void createNewKeyStore()
{
try
{
keyStore.load(null, KEYSTORE_PASSWORD);
OutputStream os = context.openFileOutput(KEYSTORE_FILE_NAME, Context.MODE_PRIVATE);
insertCertificate(keyStore, CERTIFICATE_ALIAS, downloadCertificate(CERTIFICATE_URL));
keyStore.store(os, KEYSTORE_PASSWORD);
os.close();
}
catch (KeyStoreException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void insertCertificate(KeyStore key, String alias, Certificate cert) throws KeyStoreException, Exception
{
keyStore.setCertificateEntry(CERTIFICATE_ALIAS, downloadCertificate(CERTIFICATE_URL));
}
}
Alles anzeigen
Die Konstanten oben musst du dann jeweils noch anpassen.
KEYSTORE_FILE_NAME ist einfach nur der Name der KeyStore Datei (was der name ja auch schon sagt :P). Ist eigentlich egal wie du die Datei nennst.
KEYSTORE_PASSWORD ist für das Passwort für den KeyStore, da ein KeyStore ja immer mit Passwort gesichert sein muss.
CERTIFICATE_ALIAS bin ich mir nicht ganz sicher, aber das steht beim Zertifikat immer dabei. Müsste der einfach Allgemeine Name (CN) sein.
CERTIFICATE_URL ist die genaue Adresse zum Zertifikat auf dem Server. Das ist wichtig, da ja das Zertifikat runtergeladen und in den KeyStore gespeichert wird. (Frag mich jetzt nicht, wie ich an die Adresse gekommen bin, da müsste ich auch nochmal nachgucken :P)
Näher gehe ich jetzt mal nicht auf den Code ein, dazu müsste ich mir auch kurz Zeit nehmen, aber das kriegst du bestimmt auch selber hin den zu verstehen. Viel Hokus-Pokus ist das nicht.
Und so wird das Ganze dann benutzt:
String loginUrl = "url"; // url zur Seite, die geparst werden soll
DefaultHttpClient client = new SecureHttpClient(getApplicationContext());
HttpResponse httpResponse;
HttpEntity entity;
HttpGet request = new HttpGet(loginUrl);
try
{
client.getCredentialsProvider().setCredentials(
new AuthScope("scope", 443), // müsste das selbe sein wie der ALIAS im KeyStoreHandler (ist bei mir jedenfalls der Fall)
new UsernamePasswordCredentials(name, pass)); // Login Daten
httpResponse = client.execute(request);
entiy = httpResponse.getEntity();
} catch (// exception) { // und so weiter}
Alles anzeigen
Ich hoffe ich hab nichts vergessen. Es ist vielleicht nicht optimal gelöst (siehe Exception-Handling usw.) und es ist auch nicht die einzige Lösung, aber sie hat funktioniert und das war die Hauptsache.
block_