aboutsummaryrefslogtreecommitdiffstats
path: root/libs/MemorizingTrustManager/example/src/de/duenndns
diff options
context:
space:
mode:
authorSam Whited <sam@samwhited.com>2014-10-28 12:11:51 -0400
committerSam Whited <sam@samwhited.com>2014-10-28 12:11:51 -0400
commit41d2e72be7b36a7ee9a89e3f4a4ddec8b2e9c73e (patch)
treeaec475fe700b3f7ef371d8310dd26943e440d107 /libs/MemorizingTrustManager/example/src/de/duenndns
parent89c294af11a22886b3e6be6ed0d6cfd98b3ea672 (diff)
parent9e42bff01440c1351946a432126d5a1b87fb7c78 (diff)
Subtree merged in MemorizingTrustManager
Diffstat (limited to 'libs/MemorizingTrustManager/example/src/de/duenndns')
m---------libs/MemorizingTrustManager0
-rw-r--r--libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/JULHandler.java169
-rw-r--r--libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/MTMExample.java143
3 files changed, 312 insertions, 0 deletions
diff --git a/libs/MemorizingTrustManager b/libs/MemorizingTrustManager
deleted file mode 160000
-Subproject fad835037adc1bd313bb56b694426fca4eb6734
diff --git a/libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/JULHandler.java b/libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/JULHandler.java
new file mode 100644
index 000000000..40f71f580
--- /dev/null
+++ b/libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/JULHandler.java
@@ -0,0 +1,169 @@
+package de.duenndns.mtmexample;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringBufferInputStream;
+import java.io.StringWriter;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import android.util.Log;
+
+/**
+ * A <code>java.util.logging</code> (JUL) Handler for Android.
+ * <p>
+ * If you want fine-grained control over MTM's logging, you can copy this
+ * class to your code base and call the static {@link #initialize()} method.
+ * </p>
+ * <p>
+ * This JUL Handler passes log messages sent to JUL to the Android log, while
+ * keeping the format and stack traces of optionally supplied Exceptions. It
+ * further allows to install a {@link DebugLogSettings} class via
+ * {@link #setDebugLogSettings(DebugLogSettings)} that determines whether JUL log messages of
+ * level {@link java.util.logging.Level#FINE} or lower are logged. This gives
+ * the application developer more control over the logged messages, while
+ * allowing a library developer to place debug log messages without risking to
+ * spam the Android log.
+ * </p>
+ * <p>
+ * If there are no {@code DebugLogSettings} configured, then all messages sent
+ * to JUL will be logged.
+ * </p>
+ *
+ * @author Florian Schmaus
+ *
+ */
+@SuppressWarnings("deprecation")
+public class JULHandler extends Handler {
+
+ /** Implement this interface to toggle debug logging.
+ */
+ public interface DebugLogSettings {
+ public boolean isDebugLogEnabled();
+ }
+
+ private static final String CLASS_NAME = JULHandler.class.getName();
+
+ /**
+ * The global LogManager configuration.
+ * <p>
+ * This configures:
+ * <ul>
+ * <li> JULHandler as the default handler for all log messages
+ * <li> A default log level FINEST (300). Meaning that log messages of a level 300 or higher a
+ * logged
+ * </ul>
+ * </p>
+ */
+ private static final InputStream LOG_MANAGER_CONFIG = new StringBufferInputStream(
+// @formatter:off
+"handlers = " + CLASS_NAME + '\n' +
+".level = FINEST"
+);
+// @formatter:on
+
+ // Constants for Android vs. JUL debug level comparisons
+ private static final int FINE_INT = Level.FINE.intValue();
+ private static final int INFO_INT = Level.INFO.intValue();
+ private static final int WARN_INT = Level.WARNING.intValue();
+ private static final int SEVE_INT = Level.SEVERE.intValue();
+
+ private static final Logger LOGGER = Logger.getLogger(CLASS_NAME);
+
+ /** A formatter that creates output similar to Android's Log.x. */
+ private static final Formatter FORMATTER = new Formatter() {
+ @Override
+ public String format(LogRecord logRecord) {
+ Throwable thrown = logRecord.getThrown();
+ if (thrown != null) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, false);
+ pw.write(logRecord.getMessage() + ' ');
+ thrown.printStackTrace(pw);
+ pw.flush();
+ return sw.toString();
+ } else {
+ return logRecord.getMessage();
+ }
+ }
+ };
+
+ private static DebugLogSettings sDebugLogSettings;
+ private static boolean initialized = false;
+
+ public static void initialize() {
+ try {
+ LogManager.getLogManager().readConfiguration(LOG_MANAGER_CONFIG);
+ initialized = true;
+ } catch (IOException e) {
+ Log.e("JULHandler", "Can not initialize configuration", e);
+ }
+ if (initialized) LOGGER.info("Initialzied java.util.logging logger");
+ }
+
+ public static void setDebugLogSettings(DebugLogSettings debugLogSettings) {
+ if (!isInitialized()) initialize();
+ sDebugLogSettings = debugLogSettings;
+ }
+
+ public static boolean isInitialized() {
+ return initialized;
+ }
+
+ public JULHandler() {
+ setFormatter(FORMATTER);
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public boolean isLoggable(LogRecord record) {
+ final boolean debugLog = sDebugLogSettings == null ? true : sDebugLogSettings
+ .isDebugLogEnabled();
+
+ if (record.getLevel().intValue() <= FINE_INT) {
+ return debugLog;
+ }
+ return true;
+ }
+
+ /** JUL method that forwards log records to Android's LogCat. */
+ @Override
+ public void publish(LogRecord record) {
+ if (!isLoggable(record)) return;
+
+ final int priority = getAndroidPriority(record.getLevel());
+ final String tag = substringAfterLastDot(record.getSourceClassName());
+ final String msg = getFormatter().format(record);
+
+ Log.println(priority, tag, msg);
+ }
+
+ /** Helper to convert JUL verbosity levels to Android's Log. */
+ private static int getAndroidPriority(Level level) {
+ int value = level.intValue();
+ if (value >= SEVE_INT) {
+ return Log.ERROR;
+ } else if (value >= WARN_INT) {
+ return Log.WARN;
+ } else if (value >= INFO_INT) {
+ return Log.INFO;
+ } else {
+ return Log.DEBUG;
+ }
+ }
+
+ /** Helper to extract short class names. */
+ private static String substringAfterLastDot(String s) {
+ return s.substring(s.lastIndexOf('.') + 1).trim();
+ }
+}
diff --git a/libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/MTMExample.java b/libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/MTMExample.java
new file mode 100644
index 000000000..0d16ae82f
--- /dev/null
+++ b/libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/MTMExample.java
@@ -0,0 +1,143 @@
+package de.duenndns.mtmexample;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.Window;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.net.URL;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.X509TrustManager;
+
+import de.duenndns.ssl.MemorizingTrustManager;
+
+/**
+ * Example to demonstrate the use of MemorizingTrustManager on HTTPS
+ * sockets.
+ */
+public class MTMExample extends Activity implements OnClickListener
+{
+ MemorizingTrustManager mtm;
+
+ TextView content;
+ HostnameVerifier defaultverifier;
+ EditText urlinput;
+ String text;
+ Handler hdlr;
+
+ /** Creates the Activity and registers a MemorizingTrustManager. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ JULHandler.initialize();
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.mtmexample);
+
+
+ // set up gui elements
+ findViewById(R.id.connect).setOnClickListener(this);
+ content = (TextView)findViewById(R.id.content);
+ urlinput = (EditText)findViewById(R.id.url);
+
+ // register handler for background thread
+ hdlr = new Handler();
+
+ // Here, the MemorizingTrustManager is activated for HTTPS
+ try {
+ // set location of the keystore
+ MemorizingTrustManager.setKeyStoreFile("private", "sslkeys.bks");
+
+ // register MemorizingTrustManager for HTTPS
+ SSLContext sc = SSLContext.getInstance("TLS");
+ mtm = new MemorizingTrustManager(this);
+ sc.init(null, new X509TrustManager[] { mtm },
+ new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier(
+ mtm.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()));
+
+ // disable redirects to reduce possible confusion
+ HttpsURLConnection.setFollowRedirects(false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /** Updates the screen content from a background thread. */
+ void setText(final String s, final boolean progress) {
+ text = s;
+ hdlr.post(new Runnable() {
+ public void run() {
+ content.setText(s);
+ setProgressBarIndeterminateVisibility(progress);
+ }
+ });
+ }
+
+ /** Spawns a new thread connecting to the specified URL.
+ * The result of the request is displayed on the screen.
+ * @param urlString a HTTPS URL to connect to.
+ */
+ void connect(final String urlString) {
+ new Thread() {
+ public void run() {
+ try {
+ URL u = new URL(urlString);
+ HttpsURLConnection c = (HttpsURLConnection)u.openConnection();
+ c.connect();
+ setText("" + c.getResponseCode() + " "
+ + c.getResponseMessage(), false);
+ c.disconnect();
+ } catch (Exception e) {
+ setText(e.toString(), false);
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
+
+ /** Reacts on the connect Button press. */
+ @Override
+ public void onClick(View view) {
+ String url = urlinput.getText().toString();
+ setText("Loading " + url, true);
+ setProgressBarIndeterminateVisibility(true);
+ connect(url);
+ }
+
+ /** React on the "Manage Certificates" button press. */
+ public void onManage(View view) {
+ final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.select_dialog_item, aliases);
+ new AlertDialog.Builder(this).setTitle("Tap Certificate to Delete")
+ .setNegativeButton(android.R.string.cancel, null)
+ .setAdapter(adapter, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ try {
+ String alias = aliases.get(which);
+ mtm.deleteCertificate(alias);
+ setText("Deleted " + alias, false);
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ setText("Error: " + e.getLocalizedMessage(), false);
+ }
+ }
+ })
+ .create().show();
+ }
+}