changeset 1825:2ae8438ee9d2

Keyring service might block forever storing passwords on newer distributions Add a libsecret based JNI implementation which is preferred over an libgnome-keyring based one. The JNI build is now autotools based so as to be able to select an implementation at build time. PR2660 Reviewed-by: neugens, omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-October/016616.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-October/016640.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Mon, 05 Oct 2015 11:58:01 -0400
parents 96c0923a42e3
children 1240d8f621f3
files .hgignore README keyring/Makefile keyring/Makefile.am keyring/README keyring/configure.ac keyring/pom.xml keyring/src/main/native/GnomeKeyringLibraryNative.c keyring/src/main/native/Makefile.am keyring/src/main/native/libgnome-keyring/GnomeKeyringLibraryNative.c keyring/src/main/native/libgnome-keyring/Makefile keyring/src/main/native/libsecret/LibsecretKeyringLibraryNative.c keyring/src/main/native/libsecret/Makefile
diffstat 13 files changed, 602 insertions(+), 261 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Oct 01 14:24:31 2015 +0200
+++ b/.hgignore	Mon Oct 05 11:58:01 2015 -0400
@@ -3,6 +3,20 @@
 # pom. As it's derivable, hgignore it :)
 integration-tests/standalone/dependency-reduced-pom.xml
 
+# Keyring autogenerated files
+keyring/Makefile.in
+keyring/Makefile
+keyring/aclocal.m4
+keyring/autom4*
+keyring/compile
+keyring/config.log
+keyring/config.status
+keyring/configure
+keyring/install-sh
+keyring/missing
+keyring/src/main/native/Makefile
+keyring/src/main/native/Makefile.in
+
 syntax: glob
 target/*
 bin/*
--- a/README	Thu Oct 01 14:24:31 2015 +0200
+++ b/README	Mon Oct 05 11:58:01 2015 -0400
@@ -43,7 +43,7 @@
   correctly with just a JRE.
 
 * Maven (it will download all the java dependencies for you)
-* Make + GCC
+* Make, GCC + autoconf
 * MongoDB server
 
   Thermostat requires mongodb (http://www.mongodb.org/) server >= 2.0.0.
@@ -53,7 +53,8 @@
     yum install mongodb-server
 
 * Either a /etc/os-release file or lsb_release
-* Gnome Keyring Daemon development libraries plus pkg-configs
+* Gnome Keyring Daemon development libraries plus pkg-configs. Either libsecret
+  based or a libgnome-keyring based solution is supported.
 * GTK 2+ development libraries plus pkg-configs
 
   Gnome Keyring/GTK2+ development libraries are required at build time.
@@ -61,6 +62,10 @@
   You should check your distribution for the exact name of the libraries, on
   Fedora based distributions you can obtain it via:
 
+    dnf install libsecret-devel gtk2-devel
+
+  or
+   
     yum install libgnome-keyring-devel gtk2-devel
 
   on RHEL/CentOS 6.x via:
--- a/keyring/Makefile	Thu Oct 01 14:24:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-CC         = gcc
-JAVAH      = javah
-MYCFLAGS   = -c -Wall -fPIC
-MYLDFLAGS  = -fPIC -shared
-COPY       = cp -a
-
-CLASSPATH  = target/classes/
-TARGET_DIR = target
-
-INCLUDE    = -I $(TARGET_DIR) -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux
-SOURCES    = src/main/native/GnomeKeyringLibraryNative.c
-TARGET     = $(TARGET_DIR)/GnomeKeyringLibraryNative.c
-OBJECTS    = $(TARGET:.c=.o)
-
-EXECUTABLE = libGnomeKeyringWrapper.so
-
-MYCFLAGS   += `pkg-config --cflags gnome-keyring-1`
-MYLDFLAGS  += `pkg-config --libs gnome-keyring-1`
-
-.PHONY:
-JNI_LIST = com.redhat.thermostat.utils.keyring.impl.KeyringImpl
-
-$(JNI_LIST):
-	$(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST)
-
-all: $(JNI_LIST) init $(SOURCES) $(EXECUTABLE)
-
-.PHONY:
-init:
-	$(COPY) $(SOURCES) $(TARGET)
-
-$(EXECUTABLE): $(OBJECTS)
-	$(CC) $(OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS)
-
-.c.o:
-	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
-
-clean-lib:
-	rm $(TARGET_DIR)/$(EXECUTABLE)
-	
-clean-obj:
-	rm $(OBJECTS) $(TARGET)
-	
-clean: clean-obj clean-lib
-	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/Makefile.am	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,2 @@
+SUBDIRS = src/main/native
+dist_doc_DATA = README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/README	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,14 @@
+Thermostat Keyring service's JNI library.
+
+- A libsecret based implementation is preferred over
+- A libgnome-keyring based implementation
+
+If libsecret is not available a libgnome-keyring based implementation will be
+built. If both libgnome-keyring and libsecret are available, the libsecret
+based implementation will take precedence. 
+
+Please ensure you have the preferred library's devel packages installed.
+
+$ autoreconf --install
+$ ./configure
+$ make
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/configure.ac	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,13 @@
+AC_INIT([thermostat-keyring-native], [1.0], [thermostat@icedtea.classpath.org])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+AC_PROG_CC
+PKG_CHECK_MODULES(LIBSECRET, [libsecret-1],
+   [AC_SUBST([JNI_SOURCE_DIR], [libsecret])],
+   [PKG_CHECK_MODULES([LIBGNOME_KEYRING], [gnome-keyring-1],
+       [AC_SUBST([JNI_SOURCE_DIR], [libgnome-keyring])])
+])
+AC_CONFIG_FILES([
+ Makefile
+ src/main/native/Makefile
+])
+AC_OUTPUT
--- a/keyring/pom.xml	Thu Oct 01 14:24:31 2015 +0200
+++ b/keyring/pom.xml	Mon Oct 05 11:58:01 2015 -0400
@@ -87,24 +87,48 @@
         <version>1.2.1</version>
         <executions>  
           <execution>
+            <id>id1</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <executable>autoreconf</executable>
+              <arguments>
+                <argument>--install</argument>
+              </arguments>
+            </configuration>
+          </execution>  
+          <execution>
+            <id>id2</id>
             <phase>compile</phase>
             <goals>
               <goal>exec</goal>
             </goals>
+            <configuration>
+              <executable>./configure</executable>
+            </configuration>
+          </execution>  
+          <execution>
+            <id>id3</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <executable>make</executable>
+              <arguments>
+                <argument>all</argument>
+              </arguments>
+              <systemProperties>
+                <systemProperty>
+                  <key>JAVA_HOME</key>
+                  <value>${java.home}</value>
+                </systemProperty>
+              </systemProperties>
+            </configuration>
           </execution>  
         </executions>
-        <configuration>
-          <executable>make</executable>
-          <arguments>
-            <argument>all</argument>
-          </arguments>
-          <systemProperties>
-            <systemProperty>
-              <key>JAVA_HOME</key>
-              <value>${java.home}</value>
-            </systemProperty>
-          </systemProperties>
-        </configuration>
       </plugin>
     </plugins>
     <pluginManagement>
--- a/keyring/src/main/native/GnomeKeyringLibraryNative.c	Thu Oct 01 14:24:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-#include "com_redhat_thermostat_utils_keyring_impl_KeyringImpl.h"
-
-#include <jni.h>
-#include <glib.h>
-#include <gnome-keyring.h>
-#include <stdlib.h>
-#include <string.h>
-
-GnomeKeyringPasswordSchema thermostat_schema = {
-    GNOME_KEYRING_ITEM_GENERIC_SECRET,
-    {
-        { "username", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
-        { "url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
-        { NULL, 0 }
-    }
-};
-
-static void init(void) {
-    if (g_get_application_name() == NULL) {
-        g_set_application_name("Thermostat");
-    }
-}
-
-JNIEXPORT jboolean JNICALL
-Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperSavePasswordNative
-  (JNIEnv *env, jclass GnomeKeyringLibraryNativeClass, jstring jurl, jstring juserName, jbyteArray jpassword, jstring jdescription)
-{
-    int passIndex;
-    const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
-    if (url == NULL) {
-        return JNI_FALSE;
-    }
-    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
-    if (userName == NULL) {
-        (*env)->ReleaseStringUTFChars(env, jurl, url);
-        return JNI_FALSE;
-    }
-
-    jsize passwordLength = (*env)->GetArrayLength(env, jpassword);
-    jbyte *password = (*env)->GetByteArrayElements(env, jpassword, NULL);
-    if (password == NULL) {
-        (*env)->ReleaseStringUTFChars(env, jurl, url);
-        (*env)->ReleaseStringUTFChars(env, juserName, userName);
-        return JNI_FALSE;
-    }
-
-    /* Make into null terminated (g)char * to make gnome api happy */
-    gchar *gpassword = malloc(sizeof(gchar) * (passwordLength + 1));
-    if (gpassword == NULL) {
-        (*env)->ReleaseStringUTFChars(env, jurl, url);
-        (*env)->ReleaseStringUTFChars(env, juserName, userName);
-        for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
-            password[passIndex] = '\0';
-        }
-        (*env)->ReleaseByteArrayElements(env, jpassword, password, JNI_ABORT);
-        return JNI_FALSE;
-    }
-    for (passIndex = 0; passIndex < passwordLength; passIndex++) {
-        gpassword[passIndex] = (gchar) (password[passIndex]);
-    }
-    gpassword[passwordLength] = (gchar) '\0';
-
-    /* Overwrite original array, release back to java-land. */
-    for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
-        password[passIndex] = '\0';
-    }
-    (*env)->ReleaseByteArrayElements(env, jpassword, password, JNI_ABORT);
-
-    const char *description = (*env)->GetStringUTFChars(env, jdescription, NULL);
-    if (description == NULL) {
-    	(*env)->ReleaseStringUTFChars(env, jurl, url);
-        (*env)->ReleaseStringUTFChars(env, juserName, userName);
-        for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
-            gpassword[passIndex] = (gchar) '\0';
-        }
-        free(gpassword);
-        return JNI_FALSE;
-    }
-
-    init();
-    GnomeKeyringResult res = gnome_keyring_store_password_sync(&thermostat_schema,
-                                                                GNOME_KEYRING_DEFAULT,
-                                                                description,
-                                                                gpassword,
-                                                                "username", userName,
-                                                                "url", url,
-                                                                NULL);
-    (*env)->ReleaseStringUTFChars(env, jurl, url);
-    (*env)->ReleaseStringUTFChars(env, juserName, userName);
-    for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
-        gpassword[passIndex] = '\0';
-    }
-    free(gpassword);
-    (*env)->ReleaseStringUTFChars(env, jdescription, description);
-
-    return (res == GNOME_KEYRING_RESULT_OK) ? JNI_TRUE : JNI_FALSE;
-}
-
-JNIEXPORT jbyteArray JNICALL
-Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperGetPasswordNative
-  (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName)
-{
-	const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
-    if (url == NULL) {
-
-        return NULL;
-    }
-
-    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
-    if (userName == NULL) {
-    	(*env)->ReleaseStringUTFChars(env, jurl, url);
-        return NULL;
-    }
-
-    gchar *password = NULL;
-    GnomeKeyringResult res;
-
-    init();
-    res = gnome_keyring_find_password_sync(&thermostat_schema,
-                                           &password,
-                                           "username", userName,
-                                           "url", url,
-                                           NULL);
-
-    (*env)->ReleaseStringUTFChars(env, jurl, url);
-    (*env)->ReleaseStringUTFChars(env, juserName, userName);
-
-    if (res == GNOME_KEYRING_RESULT_OK) {
-        const jbyte *jbytePassword = (const jbyte *) password;
-
-        jsize passwordLength = strlen(password);
-        jbyteArray jpassword = (*env)->NewByteArray(env, passwordLength);
-        (*env)->SetByteArrayRegion(env, jpassword, 0, passwordLength, jbytePassword);
-        gnome_keyring_free_password(password);
-        return jpassword;
-    } else {
-        return NULL;
-    }
-}
-
-JNIEXPORT jboolean JNICALL
-Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperClearPasswordNative
-  (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName)
-{
-    const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
-    if (url == NULL) {
-        return JNI_FALSE;
-    }
-    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
-    if (userName == NULL) {
-        (*env)->ReleaseStringUTFChars(env, jurl, url);
-        return JNI_FALSE;
-    }
-
-    init();
-    GnomeKeyringResult res = gnome_keyring_delete_password_sync(&thermostat_schema,
-                                                                "username", userName,
-                                                                "url", url,
-                                                                NULL);
-
-    (*env)->ReleaseStringUTFChars(env, jurl, url);
-    (*env)->ReleaseStringUTFChars(env, juserName, userName);
-
-    return (res == GNOME_KEYRING_RESULT_OK) ? JNI_TRUE : JNI_FALSE;
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/src/main/native/Makefile.am	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,1 @@
+SUBDIRS = @JNI_SOURCE_DIR@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/src/main/native/libgnome-keyring/GnomeKeyringLibraryNative.c	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+#include "com_redhat_thermostat_utils_keyring_impl_KeyringImpl.h"
+
+#include <jni.h>
+#include <glib.h>
+#include <gnome-keyring.h>
+#include <stdlib.h>
+#include <string.h>
+
+GnomeKeyringPasswordSchema thermostat_schema = {
+    GNOME_KEYRING_ITEM_GENERIC_SECRET,
+    {
+        { "username", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+        { "url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+        { NULL, 0 }
+    }
+};
+
+static void init(void) {
+    if (g_get_application_name() == NULL) {
+        g_set_application_name("Thermostat");
+    }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperSavePasswordNative
+  (JNIEnv *env, jclass GnomeKeyringLibraryNativeClass, jstring jurl, jstring juserName, jbyteArray jpassword, jstring jdescription)
+{
+    int passIndex;
+    const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
+    if (url == NULL) {
+        return JNI_FALSE;
+    }
+    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
+    if (userName == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        return JNI_FALSE;
+    }
+
+    jsize passwordLength = (*env)->GetArrayLength(env, jpassword);
+    jbyte *password = (*env)->GetByteArrayElements(env, jpassword, NULL);
+    if (password == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        (*env)->ReleaseStringUTFChars(env, juserName, userName);
+        return JNI_FALSE;
+    }
+
+    /* Make into null terminated (g)char * to make gnome api happy */
+    gchar *gpassword = malloc(sizeof(gchar) * (passwordLength + 1));
+    if (gpassword == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        (*env)->ReleaseStringUTFChars(env, juserName, userName);
+        for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+            password[passIndex] = '\0';
+        }
+        (*env)->ReleaseByteArrayElements(env, jpassword, password, JNI_ABORT);
+        return JNI_FALSE;
+    }
+    for (passIndex = 0; passIndex < passwordLength; passIndex++) {
+        gpassword[passIndex] = (gchar) (password[passIndex]);
+    }
+    gpassword[passwordLength] = (gchar) '\0';
+
+    /* Overwrite original array, release back to java-land. */
+    for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+        password[passIndex] = '\0';
+    }
+    (*env)->ReleaseByteArrayElements(env, jpassword, password, JNI_ABORT);
+
+    const char *description = (*env)->GetStringUTFChars(env, jdescription, NULL);
+    if (description == NULL) {
+    	(*env)->ReleaseStringUTFChars(env, jurl, url);
+        (*env)->ReleaseStringUTFChars(env, juserName, userName);
+        for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+            gpassword[passIndex] = (gchar) '\0';
+        }
+        free(gpassword);
+        return JNI_FALSE;
+    }
+
+    init();
+    GnomeKeyringResult res = gnome_keyring_store_password_sync(&thermostat_schema,
+                                                                GNOME_KEYRING_DEFAULT,
+                                                                description,
+                                                                gpassword,
+                                                                "username", userName,
+                                                                "url", url,
+                                                                NULL);
+    (*env)->ReleaseStringUTFChars(env, jurl, url);
+    (*env)->ReleaseStringUTFChars(env, juserName, userName);
+    for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+        gpassword[passIndex] = '\0';
+    }
+    free(gpassword);
+    (*env)->ReleaseStringUTFChars(env, jdescription, description);
+
+    return (res == GNOME_KEYRING_RESULT_OK) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperGetPasswordNative
+  (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName)
+{
+	const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
+    if (url == NULL) {
+
+        return NULL;
+    }
+
+    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
+    if (userName == NULL) {
+    	(*env)->ReleaseStringUTFChars(env, jurl, url);
+        return NULL;
+    }
+
+    gchar *password = NULL;
+    GnomeKeyringResult res;
+
+    init();
+    res = gnome_keyring_find_password_sync(&thermostat_schema,
+                                           &password,
+                                           "username", userName,
+                                           "url", url,
+                                           NULL);
+
+    (*env)->ReleaseStringUTFChars(env, jurl, url);
+    (*env)->ReleaseStringUTFChars(env, juserName, userName);
+
+    if (res == GNOME_KEYRING_RESULT_OK) {
+        const jbyte *jbytePassword = (const jbyte *) password;
+
+        jsize passwordLength = strlen(password);
+        jbyteArray jpassword = (*env)->NewByteArray(env, passwordLength);
+        (*env)->SetByteArrayRegion(env, jpassword, 0, passwordLength, jbytePassword);
+        gnome_keyring_free_password(password);
+        return jpassword;
+    } else {
+        return NULL;
+    }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperClearPasswordNative
+  (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName)
+{
+    const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
+    if (url == NULL) {
+        return JNI_FALSE;
+    }
+    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
+    if (userName == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        return JNI_FALSE;
+    }
+
+    init();
+    GnomeKeyringResult res = gnome_keyring_delete_password_sync(&thermostat_schema,
+                                                                "username", userName,
+                                                                "url", url,
+                                                                NULL);
+
+    (*env)->ReleaseStringUTFChars(env, jurl, url);
+    (*env)->ReleaseStringUTFChars(env, juserName, userName);
+
+    return (res == GNOME_KEYRING_RESULT_OK) ? JNI_TRUE : JNI_FALSE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/src/main/native/libgnome-keyring/Makefile	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,45 @@
+CC         = gcc
+JAVAH      = javah
+MYCFLAGS   = -c -Wall -fPIC
+MYLDFLAGS  = -fPIC -shared
+COPY       = cp -a
+
+CLASSPATH  = ../../../../target/classes/
+TARGET_DIR = ../../../../target
+
+INCLUDE    = -I $(TARGET_DIR) -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux
+SOURCES    = GnomeKeyringLibraryNative.c
+TARGET     = $(TARGET_DIR)/GnomeKeyringLibraryNative.c
+OBJECTS    = $(TARGET:.c=.o)
+
+EXECUTABLE = libGnomeKeyringWrapper.so
+
+MYCFLAGS   += `pkg-config --cflags gnome-keyring-1`
+MYLDFLAGS  += `pkg-config --libs gnome-keyring-1`
+
+.PHONY:
+JNI_LIST = com.redhat.thermostat.utils.keyring.impl.KeyringImpl
+
+$(JNI_LIST):
+	$(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST)
+
+all: $(JNI_LIST) init $(SOURCES) $(EXECUTABLE)
+
+.PHONY:
+init:
+	$(COPY) $(SOURCES) $(TARGET)
+
+$(EXECUTABLE): $(OBJECTS)
+	$(CC) $(OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS)
+
+.c.o:
+	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
+
+clean-lib:
+	rm -f $(TARGET_DIR)/$(EXECUTABLE)
+	
+clean-obj:
+	rm -f $(OBJECTS) $(TARGET)
+	
+clean: clean-obj clean-lib
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/src/main/native/libsecret/LibsecretKeyringLibraryNative.c	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2012-2015 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+#include "com_redhat_thermostat_utils_keyring_impl_KeyringImpl.h"
+
+#include <jni.h>
+#include <glib.h>
+#include <libsecret/secret.h>
+#include <stdlib.h>
+#include <string.h>
+
+SecretSchema thermostat_schema = {
+        "com.redhat.thermostat.password", SECRET_SCHEMA_NONE,
+        {
+            { "username", SECRET_SCHEMA_ATTRIBUTE_STRING },
+            { "url", SECRET_SCHEMA_ATTRIBUTE_STRING },
+            { "NULL", 0 }
+        }
+    };
+
+static void init(void) {
+    if (g_get_application_name() == NULL) {
+        g_set_application_name("Thermostat");
+    }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperSavePasswordNative
+  (JNIEnv *env, jclass GnomeKeyringLibraryNativeClass, jstring jurl, jstring juserName, jbyteArray jpassword, jstring jdescription)
+{
+    int passIndex;
+    const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
+    if (url == NULL) {
+        return JNI_FALSE;
+    }
+    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
+    if (userName == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        return JNI_FALSE;
+    }
+
+    jsize passwordLength = (*env)->GetArrayLength(env, jpassword);
+    jbyte *password = (*env)->GetByteArrayElements(env, jpassword, NULL);
+    if (password == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        (*env)->ReleaseStringUTFChars(env, juserName, userName);
+        return JNI_FALSE;
+    }
+
+    /* Make into null terminated (g)char * to make gnome api happy */
+    gchar *gpassword = malloc(sizeof(gchar) * (passwordLength + 1));
+    if (gpassword == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        (*env)->ReleaseStringUTFChars(env, juserName, userName);
+        for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+            password[passIndex] = '\0';
+        }
+        (*env)->ReleaseByteArrayElements(env, jpassword, password, JNI_ABORT);
+        return JNI_FALSE;
+    }
+    for (passIndex = 0; passIndex < passwordLength; passIndex++) {
+        gpassword[passIndex] = (gchar) (password[passIndex]);
+    }
+    gpassword[passwordLength] = (gchar) '\0';
+
+    /* Overwrite original array, release back to java-land. */
+    for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+        password[passIndex] = '\0';
+    }
+    (*env)->ReleaseByteArrayElements(env, jpassword, password, JNI_ABORT);
+
+    const char *description = (*env)->GetStringUTFChars(env, jdescription, NULL);
+    if (description == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        (*env)->ReleaseStringUTFChars(env, juserName, userName);
+        for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+            gpassword[passIndex] = (gchar) '\0';
+        }
+        free(gpassword);
+        return JNI_FALSE;
+    }
+
+    init();
+    GError *error = NULL;
+    jboolean is_success = JNI_TRUE;
+    secret_password_store_sync(&thermostat_schema,
+                               SECRET_COLLECTION_DEFAULT,
+                               description,
+                               gpassword,
+                               NULL,
+                               &error,
+                               "username", userName,
+                               "url", url,
+                               NULL);
+    if (error != NULL) {
+        is_success = JNI_FALSE;
+        g_error_free (error);
+    }
+    (*env)->ReleaseStringUTFChars(env, jurl, url);
+    (*env)->ReleaseStringUTFChars(env, juserName, userName);
+    for (passIndex = 0; passIndex < (int) passwordLength; passIndex++) {
+        gpassword[passIndex] = '\0';
+    }
+    free(gpassword);
+    (*env)->ReleaseStringUTFChars(env, jdescription, description);
+
+    return is_success;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperGetPasswordNative
+  (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName)
+{
+    const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
+    if (url == NULL) {
+        return NULL;
+    }
+
+    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
+    if (userName == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        return NULL;
+    }
+
+    gchar *password = NULL;
+    GError *error = NULL;
+
+    init();
+    password = secret_password_lookup_sync(&thermostat_schema,
+                                           NULL,
+                                           &error,
+                                           "username", userName,
+                                           "url", url,
+                                           NULL);
+
+    (*env)->ReleaseStringUTFChars(env, jurl, url);
+    (*env)->ReleaseStringUTFChars(env, juserName, userName);
+
+    if (error == NULL) {
+        // Password may be null if not found in secret store
+        if (password == NULL) {
+            return NULL;
+        }
+        const jbyte *jbytePassword = (const jbyte *) password;
+
+        jsize passwordLength = strlen(password);
+        jbyteArray jpassword = (*env)->NewByteArray(env, passwordLength);
+        (*env)->SetByteArrayRegion(env, jpassword, 0, passwordLength, jbytePassword);
+        secret_password_free(password);
+        return jpassword;
+    } else {
+        g_error_free(error);
+        return NULL;
+    }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperClearPasswordNative
+  (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName)
+{
+    const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
+    if (url == NULL) {
+        return JNI_FALSE;
+    }
+    const char *userName = (*env)->GetStringUTFChars(env, juserName, NULL);
+    if (userName == NULL) {
+        (*env)->ReleaseStringUTFChars(env, jurl, url);
+        return JNI_FALSE;
+    }
+
+    init();
+    GError *error = NULL;
+    jboolean is_success = JNI_TRUE;
+    secret_password_clear_sync(&thermostat_schema,
+                               NULL,
+                               &error,
+                               "username", userName,
+                               "url", url,
+                               NULL);
+
+    if (error != NULL) {
+        is_success = JNI_FALSE;
+        g_error_free (error);
+    }
+    (*env)->ReleaseStringUTFChars(env, jurl, url);
+    (*env)->ReleaseStringUTFChars(env, juserName, userName);
+
+    return is_success;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keyring/src/main/native/libsecret/Makefile	Mon Oct 05 11:58:01 2015 -0400
@@ -0,0 +1,45 @@
+CC         = gcc
+JAVAH      = javah
+MYCFLAGS   = -c -Wall -fPIC
+MYLDFLAGS  = -fPIC -shared
+COPY       = cp -a
+
+CLASSPATH  = ../../../../target/classes/
+TARGET_DIR = ../../../../target
+
+INCLUDE    = -I $(TARGET_DIR) -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux
+SOURCES    = LibsecretKeyringLibraryNative.c
+TARGET     = $(TARGET_DIR)/LibsecretKeyringLibraryNative.c
+OBJECTS    = $(TARGET:.c=.o)
+
+EXECUTABLE = libGnomeKeyringWrapper.so
+
+MYCFLAGS   += `pkg-config --cflags libsecret-1`
+MYLDFLAGS  += `pkg-config --libs libsecret-1`
+
+.PHONY:
+JNI_LIST = com.redhat.thermostat.utils.keyring.impl.KeyringImpl
+
+$(JNI_LIST):
+	$(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST)
+
+all: $(JNI_LIST) init $(SOURCES) $(EXECUTABLE)
+
+.PHONY:
+init:
+	$(COPY) $(SOURCES) $(TARGET)
+
+$(EXECUTABLE): $(OBJECTS)
+	$(CC) $(OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS)
+
+.c.o:
+	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
+
+clean-lib:
+	rm -f $(TARGET_DIR)/$(EXECUTABLE)
+	
+clean-obj:
+	rm -f $(OBJECTS) $(TARGET)
+	
+clean: clean-obj clean-lib
+