Add provider plugins loader
authorSimo Sorce <simo@redhat.com>
Fri, 24 Jan 2014 19:41:11 +0000 (14:41 -0500)
committerSimo Sorce <simo@redhat.com>
Tue, 25 Feb 2014 01:30:06 +0000 (20:30 -0500)
Signed-off-by: Simo Sorce <simo@redhat.com>
ipsilon/providers/__init__.py [new file with mode: 0644]
ipsilon/providers/common.py [new file with mode: 0755]
ipsilon/root.py
ipsilon/util/data.py
ipsilon/util/plugin.py
setup.py

diff --git a/ipsilon/providers/__init__.py b/ipsilon/providers/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/ipsilon/providers/common.py b/ipsilon/providers/common.py
new file mode 100755 (executable)
index 0000000..4599735
--- /dev/null
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2014  Simo Sorce <simo@redhat.com>
+#
+# see file 'COPYING' for use and warranty information
+#
+# This program 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from ipsilon.util.plugin import PluginLoader, PluginObject
+from ipsilon.util.page import Page
+import cherrypy
+
+
+class ProviderBase(PluginObject):
+
+    def __init__(self, name, path):
+        super(ProviderBase, self).__init__()
+        self.name = name
+        self.path = path
+
+
+class ProviderPageBase(Page):
+
+    def __init__(self, site, config):
+        super(ProviderPageBase, self).__init__(site)
+        self.plugin_name = config.name
+        self.cfg = config
+
+    def GET(self, *args, **kwargs):
+        raise cherrypy.HTTPError(501)
+
+    def POST(self, *args, **kwargs):
+        raise cherrypy.HTTPError(501)
+
+    def root(self, *args, **kwargs):
+        op = getattr(self, cherrypy.request.method, self.GET)
+        if callable(op):
+            return op(*args, **kwargs)
+        else:
+            raise cherrypy.HTTPError(405)
+
+    def _debug(self, fact):
+        superfact = '%s: %s' % (self.plugin_name, fact)
+        super(ProviderPageBase, self)._debug(superfact)
+
+    def _audit(self, fact):
+        cherrypy.log('%s: %s' % (self.plugin_name, fact))
+
+
+FACILITY = 'provider_config'
+
+
+class LoadProviders(object):
+
+    def __init__(self, root, site):
+        loader = PluginLoader(LoadProviders, FACILITY, 'IdpProvider')
+        site[FACILITY] = loader.get_plugin_data()
+        providers = site[FACILITY]
+
+        available = providers['available'].keys()
+        self._debug('Available providers: %s' % str(available))
+
+        for item in providers['whitelist']:
+            self._debug('IdP Provider in whitelist: %s' % item)
+            if item not in providers['available']:
+                continue
+            self._debug('IdP Provider enabled: %s' % item)
+            providers['enabled'].append(item)
+            provider = providers['available'][item]
+            if item in providers['config']:
+                provider.set_config(providers['config'][item])
+            root.__dict__[item] = provider.get_tree(site)
+
+    def _debug(self, fact):
+        if cherrypy.config.get('debug', False):
+            cherrypy.log(fact)
index 19a47a4..413f453 100755 (executable)
@@ -22,6 +22,7 @@ from ipsilon.util import errors
 from ipsilon.login.common import Login
 from ipsilon.login.common import Logout
 from ipsilon.admin.common import Admin
+from ipsilon.providers.common import LoadProviders
 import cherrypy
 
 sites = dict()
@@ -45,6 +46,9 @@ class Root(Page):
         self.login = Login(self._site)
         self.logout = Logout(self._site)
 
+        # set up idp providers now
+        LoadProviders(self, self._site)
+
         # after all plugins are setup we can instantiate the admin pages
         self.admin = Admin(self._site)
 
index 251c998..cbd3b49 100755 (executable)
@@ -188,3 +188,69 @@ class Store(object):
         finally:
             if con:
                 con.close()
+
+    def get_data(self, plugin):
+        con = None
+        rows = []
+        try:
+            con = sqlite3.connect(self._admin_dbname)
+            cur = con.cursor()
+            cur.execute("CREATE TABLE IF NOT EXISTS " +
+                        plugin + "_data (id INTEGER, name TEXT, value TEXT)")
+            cur.execute("SELECT * FROM " + plugin + "_data")
+            rows = cur.fetchall()
+            con.commit()
+        except sqlite3.Error, e:
+            if con:
+                con.rollback()
+            cherrypy.log.error("Failed to load %s data: [%s]" % (plugin, e))
+        finally:
+            if con:
+                con.close()
+
+        data = dict()
+        for row in rows:
+            if row[0] not in data:
+                data[row[0]] = dict()
+
+            item = data[row[0]]
+            if row[1] in item:
+                if item[row[1]] is list:
+                    item[row[1]].append(row[2])
+                else:
+                    v = item[row[1]]
+                    item[row[1]] = [v, row[2]]
+            else:
+                item[row[1]] = row[2]
+
+        return data
+
+    def save_data(self, plugin, data):
+        SELECT = "SELECT name, value FROM %s_data WHERE id=?" % plugin
+        UPDATE = "UPDATE %s_data SET value=? WHERE id=? AND name=?" % plugin
+        INSERT = "INSERT INTO %s_data VALUES(?,?,?)" % plugin
+        con = None
+        try:
+            con = sqlite3.connect(self._admin_dbname)
+            cur = con.cursor()
+            for idval in data:
+                curvals = dict()
+                for row in cur.execute(SELECT, (idval,)):
+                    curvals[row[0]] = row[1]
+
+                datum = data[idval]
+                for name in datum:
+                    if name in curvals:
+                        cur.execute(UPDATE, (datum[name], idval, name))
+                    else:
+                        cur.execute(INSERT, (idval, name, datum[name]))
+
+            con.commit()
+        except sqlite3.Error, e:
+            if con:
+                con.rollback()
+            cherrypy.log.error("Failed to store %s data: [%s]" % (plugin, e))
+            raise
+        finally:
+            if con:
+                con.close()
index 2077023..16a086a 100755 (executable)
@@ -102,6 +102,7 @@ class PluginObject(object):
         self.name = None
         self._config = None
         self._options = None
+        self._data = Store()
 
     def get_config_desc(self):
         """ The configuration description is a dictionary that provides
@@ -136,3 +137,9 @@ class PluginObject(object):
         if not self._config:
             self._config = dict()
         self._config[option] = value
+
+    def get_data(self):
+        return self._data.get_data(self.name)
+
+    def save_data(self, data):
+        self._data.save_data(self.name, data)
index 80e03b5..743a4ca 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,8 @@ setup(
     name = 'ipsilon',
     version = '0.1',
     license = 'GPLv3+',
-    packages = ['ipsilon', 'ipsilon.admin', 'ipsilon.login', 'ipsilon.util'],
+    packages = ['ipsilon', 'ipsilon.admin', 'ipsilon.login',
+                'ipsilon.providers', 'ipsilon.util'],
     data_files = [('share/man/man7', ["man/ipsilon.7"]),
                   ('doc', ['COPYING']),
                   ('examples', ['examples/ipsilon.conf'])]