summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--cobbler/api.py4
-rw-r--r--cobbler/module_loader.py12
-rw-r--r--cobbler/modules/authn_configfile.py53
-rw-r--r--cobbler/modules/authz_allowall.py41
-rw-r--r--cobbler/remote.py207
-rw-r--r--config/cobbler.conf6
-rw-r--r--config/modules.conf5
-rwxr-xr-xscripts/index.py122
9 files changed, 283 insertions, 171 deletions
diff --git a/Makefile b/Makefile
index 6e8ac88..8bef981 100644
--- a/Makefile
+++ b/Makefile
@@ -50,6 +50,10 @@ devinstall:
chown -R apache /var/www/cgi-bin/cobbler
chmod -R +x /var/www/cobbler/web
+webtest: devinstall
+ /sbin/service cobblerd restart
+ /sbin/service httpd restart
+
sdist: clean messages updatewui
python setup.py sdist
diff --git a/cobbler/api.py b/cobbler/api.py
index 50ad244..e6ef88b 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -238,13 +238,13 @@ class BootAPI:
"""
return module_loader.get_module_by_name(module_name)
- def get_module_from_file(self,section,name):
+ def get_module_from_file(self,section,name,fallback=None):
"""
Looks in /etc/cobbler/modules.conf for a section called 'section'
and a key called 'name', and then returns the module that corresponds
to the value of that key.
"""
- return module_loader.get_module_from_file(section,name)
+ return module_loader.get_module_from_file(section,name,fallback)
def get_modules_in_category(self,category):
"""
diff --git a/cobbler/module_loader.py b/cobbler/module_loader.py
index dd1b757..aafe05f 100644
--- a/cobbler/module_loader.py
+++ b/cobbler/module_loader.py
@@ -73,9 +73,15 @@ def load_modules(module_path=mod_path, blacklist=None):
def get_module_by_name(name):
return MODULE_CACHE.get(name, None)
-def get_module_from_file(category,field):
-
- value = cp.get("serializers",field)
+def get_module_from_file(category,field,fallback_module_name=None):
+
+ try:
+ value = cp.get("serializers",field)
+ except:
+ if fallback_module_name is not None:
+ value = fallback_module_name
+ else:
+ raise CX(_("Cannot find config file setting for: %s") % field)
return MODULE_CACHE.get(value, None)
def get_modules_in_category(category):
diff --git a/cobbler/modules/authn_configfile.py b/cobbler/modules/authn_configfile.py
new file mode 100644
index 0000000..afdd858
--- /dev/null
+++ b/cobbler/modules/authn_configfile.py
@@ -0,0 +1,53 @@
+"""
+Authentication module that uses /etc/cobbler/auth.conf
+Choice of authentication module is in /etc/cobbler/modules.conf
+
+Copyright 2007, Red Hat, Inc
+Michael DeHaan <mdehaan@redhat.com>
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+import ConfigParser
+import sys
+from rhpl.translate import _, N_, textdomain, utf8
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+import cexceptions
+import utils
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "authn"
+
+def authenticate(username,password):
+ """
+ Validate a username/password combo, returning True/False
+ """
+
+ config_parser = ConfigParser.ConfigParser()
+ auth_conf = open("/etc/cobbler/auth.conf")
+ config_parser.readfp(auth_conf)
+ auth_conf.close()
+ user_database = config_parser.items("xmlrpc_service_users")
+ for x in user_database:
+ (db_user,db_password) = x
+ db_user = db_user.strip()
+ db_password = db_password.strip()
+ if db_user == username and db_password == password and db_password.lower() != "disabled":
+ return True
+ return False
+
+
diff --git a/cobbler/modules/authz_allowall.py b/cobbler/modules/authz_allowall.py
new file mode 100644
index 0000000..4125ed6
--- /dev/null
+++ b/cobbler/modules/authz_allowall.py
@@ -0,0 +1,41 @@
+"""
+Authorization module that allows everything, which is the default
+for new cobbler installs.
+
+Copyright 2007, Red Hat, Inc
+Michael DeHaan <mdehaan@redhat.com>
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+import ConfigParser
+import sys
+from rhpl.translate import _, N_, textdomain, utf8
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+import cexceptions
+import utils
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "authz"
+
+def authorize(user,resource,arg1=None,arg2=None):
+ """
+ Validate a user against a resource.
+ """
+ return True
+
+
diff --git a/cobbler/remote.py b/cobbler/remote.py
index b6e6a04..dcc01d1 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -21,7 +21,6 @@ import SimpleXMLRPCServer
from rhpl.translate import _, N_, textdomain, utf8
import xmlrpclib
import logging
-import ConfigParser
import random
import base64
@@ -33,14 +32,6 @@ import item_profile
import item_system
import item_repo
-config_parser = ConfigParser.ConfigParser()
-auth_conf = open("/etc/cobbler/auth.conf")
-config_parser.readfp(auth_conf)
-auth_conf.close()
-
-user_database = config_parser.items("xmlrpc_service_users")
-
-
# FIXME: make configurable?
TOKEN_TIMEOUT = 60*60 # 60 minutes
OBJECT_TIMEOUT = 60*60 # 60 minutes
@@ -374,6 +365,17 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.token_cache = {}
self.object_cache = {}
random.seed(time.time())
+ self.authn = self.api.get_module_from_file(
+ "authentication",
+ "module",
+ "authn_configfile"
+ )
+ self.authz = self.api.get_module_from_file(
+ "authorization",
+ "module",
+ "authz_allowall"
+ )
+
def __next_id(self,retry=0):
"""
@@ -394,12 +396,12 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
urandom.close()
return b64
- def __make_token(self):
+ def __make_token(self,user):
"""
Returns a new random token.
"""
b64 = self.__get_random(25)
- self.token_cache[b64] = time.time()
+ self.token_cache[b64] = (time.time(), user)
return b64
def __invalidate_expired_objects(self):
@@ -420,12 +422,12 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
timenow = time.time()
for token in self.token_cache.keys():
- tokentime = self.token_cache[token]
+ (tokentime, user) = self.token_cache[token]
if (timenow > tokentime + TOKEN_TIMEOUT):
self.logger.debug("expiring token: %s" % token)
del self.token_cache[token]
- def __validate_user(self,user,password):
+ def __validate_user(self,input_user,input_password):
"""
Returns whether this user/pass combo should be given
access to the cobbler read-write API.
@@ -433,14 +435,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
FIXME: currently looks for users in /etc/cobbler/auth.conf
Would be very nice to allow for PAM and/or just Kerberos.
"""
- for x in user_database:
- (db_user,db_password) = x
- db_user = db_user.strip()
- db_password = db_password.strip()
- if db_user == user and db_password == password and db_password.lower() != "disabled":
- return True
- else:
- return False
+ return self.authn.authenticate(input_user,input_password)
def __validate_token(self,token):
"""
@@ -454,26 +449,44 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.__invalidate_expired_tokens()
self.__invalidate_expired_objects()
if self.token_cache.has_key(token):
- self.token_cache[token] = time.time() # update to prevent timeout
+ user = self.__get_user_from_token(token)
+ self.token_cache[token] = (time.time(), user) # update to prevent timeout
return True
else:
self.logger.debug("invalid token: %s" % token)
raise CX(_("invalid token: %s" % token))
- def login(self,user,password):
+ def check_access(self,token,resource):
+ validated = self.__validate_token(token)
+ return self.__authorize(token,resource)
+
+ def __get_user_from_token(self,token):
+ if not self.token_cache.has_key(token):
+ raise CX(_("invalid token: %s") % token)
+ else:
+ return self.token_cache[token][1]
+
+ def login(self,login_user,login_password):
"""
Takes a username and password, validates it, and if successful
returns a random login token which must be used on subsequent
method calls. The token will time out after a set interval if not
used. Re-logging in permitted.
"""
- if self.__validate_user(user,password):
- token = self.__make_token()
- self.logger.info("login succeeded: %s" % user)
+ if self.__validate_user(login_user,login_password):
+ token = self.__make_token(login_user)
+ self.logger.info("login succeeded: %s" % login_user)
return token
else:
- self.logger.info("login failed: %s" % user)
- raise CX(_("login failed: %s") % user)
+ self.logger.info("login failed: %s" % login_user)
+ raise CX(_("login failed: %s") % login_user)
+
+ def __authorize(self,token,resource):
+ user = self.__get_user_from_token(token)
+ if self.authz.authorize(user,resource):
+ return True
+ else:
+ raise CX(_("user does not have access to resource: %s") % resource)
def logout(self,token):
"""
@@ -523,7 +536,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
remote.modify_distro(distro_id, 'initrd', '/foo/initrd.img', token)
remote.save_distro(distro_id, token)
"""
- self.__validate_token(token)
+ self.check_access(token,"new_distro")
return self.__store_object(item_distro.Distro(self.api._config))
def new_profile(self,token):
@@ -531,19 +544,12 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Creates a new (unconfigured) profile object. See the documentation
for new_distro as it works exactly the same.
"""
- self.__validate_token(token)
+
+ self.check_access(token,"new_profile")
return self.__store_object(item_profile.Profile(self.api._config))
def new_subprofile(self,token):
"""
- Creates a new (unconfigured) subprofile object. See the documentation
- for new_distro as it works exactly the same.
- """
- self.__validate_token(token)
- return self.__store_object(item_profile.Profile(self.api._config, is_subobject=True))
-
- def new_subprofile(self,token):
- """
A subprofile is a profile that inherits directly from another profile,
not a distro. In addition to the normal profile setup, setting
the parent variable to the name of an existing profile is also
@@ -551,7 +557,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
were regular profiles. The same XMLRPC API methods work on them as profiles
also.
"""
- self.__validate_token(token)
+ self.check_access(token,"new_subprofile")
return self.__store_object(item_profile.Profile(self.api._config,is_subobject=True))
def new_system(self,token):
@@ -559,7 +565,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Creates a new (unconfigured) system object. See the documentation
for new_distro as it works exactly the same.
"""
- self.__validate_token(token)
+ self.check_access(token,"new_system")
return self.__store_object(item_system.System(self.api._config))
def new_repo(self,token):
@@ -567,7 +573,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Creates a new (unconfigured) repo object. See the documentation
for new_distro as it works exactly the same.
"""
- self.__validate_token(token)
+ self.check_access(token,"new_repo")
return self.__store_object(item_repo.Repo(self.api._config))
def get_distro_handle(self,name,token):
@@ -576,7 +582,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
object id that can be passed in to modify_distro() or save_distro()
commands. Raises an exception if no object can be matched.
"""
- self.__validate_token(token)
+ self.check_access(token,"get_distro_handle")
self._refresh()
found = self.api.distros().find(name)
return self.__store_object(found)
@@ -587,7 +593,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
object id that can be passed in to modify_profile() or save_profile()
commands. Raises an exception if no object can be matched.
"""
- self.__validate_token(token)
+ self.check_access(token,"get_profile_handle")
self._refresh()
found = self.api.profiles().find(name)
return self.__store_object(found)
@@ -598,7 +604,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
object id that can be passed in to modify_system() or save_system()
commands. Raises an exception if no object can be matched.
"""
- self.__validate_token(token)
+ self.check_access(token,"get_system_handle")
self._refresh()
found = self.api.systems().find(name)
return self.__store_object(found)
@@ -609,7 +615,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
object id that can be passed in to modify_repo() or save_pro()
commands. Raises an exception if no object can be matched.
"""
- self.__validate_token(token)
+ self.check_access(token,"get_repo_handle")
self._refresh()
found = self.api.repos().find(name)
return self.__store_object(found)
@@ -618,7 +624,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
Saves a newly created or modified distro object to disk.
"""
- self.__validate_token(token)
+ self.check_access(token,"save_distro")
obj = self.__get_object(object_id)
return self.api.distros().add(obj,with_copy=True)
@@ -626,7 +632,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
Saves a newly created or modified profile object to disk.
"""
- self.__validate_token(token)
+ self.check_access(token,"save_profile")
obj = self.__get_object(object_id)
return self.api.profiles().add(obj,with_copy=True)
@@ -634,7 +640,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
Saves a newly created or modified system object to disk.
"""
- self.__validate_token(token)
+ self.check_access(token,"save_system")
obj = self.__get_object(object_id)
return self.api.systems().add(obj,with_copy=True)
@@ -642,7 +648,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
Saves a newly created or modified repo object to disk.
"""
- self.__validate_token(token)
+ self.check_access(token,"save_repo")
obj = self.__get_object(object_id)
return self.api.repos().add(obj,with_copy=True)
@@ -660,7 +666,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing distro object handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "modify_distro", attribute, arg)
obj = self.__get_object(object_id)
return self.__call_method(obj, attribute, arg)
@@ -669,7 +675,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing profile object handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "modify_profile", attribute, arg)
obj = self.__get_object(object_id)
return self.__call_method(obj, attribute, arg)
@@ -678,7 +684,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing system object handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "modify_system", attribute, arg)
obj = self.__get_object(object_id)
return self.__call_method(obj, attribute, arg)
@@ -687,7 +693,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing repo object handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "modify_repo", attribute, arg)
obj = self.__get_object(object_id)
return self.__call_method(obj, attribute, arg)
@@ -696,7 +702,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Deletes a distro from a collection. Note that this just requires the name
of the distro, not a handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "distro_remove", name)
rc = self.api._config.distros().remove(name)
return rc
@@ -705,7 +711,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Deletes a profile from a collection. Note that this just requires the name
of the profile, not a handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "profile_remove", name)
rc = self.api._config.profiles().remove(name)
return rc
@@ -714,7 +720,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Deletes a system from a collection. Note that this just requires the name
of the system, not a handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "system_remove", name)
rc = self.api._config.systems().remove(name)
return rc
@@ -723,7 +729,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Deletes a repo from a collection. Note that this just requires the name
of the repo, not a handle.
"""
- self.__validate_token(token)
+ self.check_access(token, "repo_remove", name)
rc = self.api._config.repos().remove(name)
return rc
@@ -738,7 +744,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Future versions of cobbler may understand how to do a cascade sync
on object edits making explicit calls to sync redundant.
"""
- self.__validate_token(token)
+ self.check_access(token, sync)
return self.api.sync()
def reposync(self,repos=[],token=None):
@@ -747,7 +753,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
reposync is very slow and probably should not be used
through the XMLRPC API, setting up reposync on nightly cron is better.
"""
- self.__validate_token(token)
+ self.check_access(token, "reposync", repos)
return self.api.reposync(repos)
def import_tree(self,mirror_url,mirror_name,network_root=None,token=None):
@@ -757,14 +763,14 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
It would be better to use the CLI. See documentation in api.py.
This command may be removed from the API in a future release.
"""
- self.__validate_token(token)
+ self.check_access(token, "import_tree")
return self.api.import_tree(mirror_url,mirror_name,network_root)
def get_kickstart_templates(self,token):
"""
Returns all of the kickstarts that are in use by the system.
"""
- self.__validate_token(token)
+ self.check_access(token, "get_kickstart_templates")
files = {}
for x in self.api.profiles():
if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<<inherit>>":
@@ -784,7 +790,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Also if living in /etc/cobbler the file must be a kickstart file.
"""
- self.__validate_token(token)
+ self.check_access(token,"read_or_write_kickstart_templates",kickstart_file,is_read)
if kickstart_file.find("..") != -1 or not kickstart_file.startswith("/"):
raise CX(_("tainted file location"))
@@ -812,8 +818,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
-# *********************************************************************************
-# *********************************************************************************
+# *********************************************************************
+# *********************************************************************
class CobblerReadWriteXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
"""
@@ -824,76 +830,3 @@ class CobblerReadWriteXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
self.allow_reuse_address = True
SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self,args)
-# *********************************************************************************
-# *********************************************************************************
-
-if __name__ == "__main__":
-
- # note: this demo requires that
- # (A) /etc/cobbler/auth.conf has a "testuser/llamas2007" account
- # (B) xmlrpc_rw_enabled is turned on /var/lib/cobbler/settings
- # (C) cobblerd is running (and restarted if changing any of the above)
- # (D) apache is configured as a reverse proxy (see cobbler.conf in /etc/httpd/conf.d)
- # this demo does not use SSL yet -- it /should/ and /can/.
-
- my_uri = "http://127.0.0.1/cobbler_api_rw"
- remote = xmlrpclib.Server(my_uri)
-
- testuser = "admin"
- testpass = "mooses9"
-
- token = remote.login(testuser,testpass)
- print token
-
- # just to make things "work"
- os.system("touch /tmp/vmlinuz")
- os.system("touch /tmp/initrd.img")
- os.system("touch /tmp/fake.ks")
-
- # now add a distro
- distro_id = remote.new_distro(token)
- remote.modify_distro(distro_id, 'name', 'example-distro',token)
- remote.modify_distro(distro_id, 'kernel', '/tmp/vmlinuz',token)
- remote.modify_distro(distro_id, 'initrd', '/tmp/initrd.img',token)
- remote.save_distro(distro_id,token)
-
- # now add a repository (that's not really mirroring anything useful)
- repo_id = remote.new_repo(token)
- remote.modify_repo(repo_id, 'name', 'example-repo', token)
- remote.modify_repo(repo_id, 'mirror', 'rsync://mirror.example.org/foo', token)
- remote.save_repo(repo_id, token)
-
- # now add a profile
- profile_id = remote.new_profile(token)
- remote.modify_profile(profile_id, 'name', 'example-profile', token)
- remote.modify_profile(profile_id, 'distro', 'example-distro', token)
- remote.modify_profile(profile_id, 'kickstart', '/tmp/fake.ks', token)
- remote.modify_profile(profile_id, 'repos', ['example-repo'], token)
- remote.save_profile(profile_id, token)
-
- # now add a system
- system_id = remote.new_system(token)
- remote.modify_system(system_id, 'name', 'example-system', token)
- remote.modify_system(system_id, 'profile', 'example-profile', token)
- remote.save_system(system_id, token)
-
- print remote.get_distros()
- print remote.get_profiles()
- print remote.get_systems()
- print remote.get_repos()
-
- print remote.get_system("AA:BB:AA:BB:AA:BB",True) # flattened
-
- # now simulate hitting a "sync" button in a WebUI
- print remote.sync(token)
-
- # the following code just tests a failed connection:
- #remote = CobblerReadWriteXMLRPCInterface(api,logger)
- #try:
- # token = remote.login("exampleuser2","examplepass")
- #except:
- # token = "fake_token"
- #print token
- #rc = remote.test(token)
- #print "test result: %s" % rc
- # print "cache: %s" % remote.token_cache
diff --git a/config/cobbler.conf b/config/cobbler.conf
index 422420d..77bfe84 100644
--- a/config/cobbler.conf
+++ b/config/cobbler.conf
@@ -39,14 +39,14 @@ BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On
AuthName Cobbler
Require valid-user
SetHandler mod_python
- PythonAccessHandler index
+
PythonAuthenHandler index
- PythonAuthZHandler index
+ #PythonAccessHandler index
+ #PythonAuthZHandler index
PythonHandler mod_python.publisher
# disable in production
PythonDebug on
- PythonAutoReload on
</Directory>
diff --git a/config/modules.conf b/config/modules.conf
index fbe710c..2d60d21 100644
--- a/config/modules.conf
+++ b/config/modules.conf
@@ -5,3 +5,8 @@ profile = serializer_yaml
system = serializer_yaml
repo = serializer_yaml
+[authentication]
+module = authn_configfile
+
+[authorization]
+module = authn_allowall
diff --git a/scripts/index.py b/scripts/index.py
index 9076d6d..fc528df 100755
--- a/scripts/index.py
+++ b/scripts/index.py
@@ -13,60 +13,130 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""
-# TO DO:
-# connect backend authn via cobbler XMLRPC (non-RW) API
-# connect backend authz via cobbler XMLRPC (RW) API
+# still TODO:
# serve up Web UI through this interface, via tokens in headers
-# make REST interface for read/write commands (also?)
from mod_python import apache
+from mod_python import Session
+import xmlrpclib
+
+XMLRPC_SERVER = "http://127.0.0.1/cobbler_api_rw"
+
+#=======================================
+
+class ServerProxy(xmlrpclib.ServerProxy):
+
+ """
+ Establishes a connection from the mod_python
+ web interface to cobblerd, which incidentally
+ is also being proxied by Apache.
+ """
+
+ def __init__(self, url=None):
+ xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
+
+xmlrpc_server = ServerProxy(XMLRPC_SERVER)
+
+#=======================================
def __get_user(req):
+ """
+ What user are we logged in as?
+ """
req.add_common_vars()
env_vars = req.subprocess_env.copy()
return env_vars["REMOTE_USER"]
+def __get_session(req):
+ """
+ Get/Create the Apache Session Object
+ FIXME: any reason to not use MemorySession?
+ """
+ if not hasattr(req,"session"):
+ req.session = Session.MemorySession(req)
+ return req.session
+
+#======================================================
+
def index(req):
- user = __get_user(req)
- path = req.uri
- return "Hello, %s, %s" % (user, path)
+
+ """
+ Right now, index serves everything.
+
+ Hitting this URL means we've already cleared authn/authz
+ but we still need to use the token for all remote requests.
+
+ FIXME: deal with query strings and defer to CobblerWeb.py
+ """
+
+ my_user = __get_user(req)
+ my_uri = req.uri
+
+ sess = __get_session(req)
+ token = sess['cobbler_token']
+
+ return "it seems to be all good: %s" % token
+
+#======================================================
def hello(req):
+
+ """
+ This is just another example for the publisher handler.
+ """
+
user = __get_user(req)
path = req.uri
return "We are in hello(%s)" % path
-def authenhandler(req):
+#======================================================
- pw = req.get_basic_auth_pw()
- user = req.user
+def authenhandler(req):
- # FIXME: poll cobbler_api (not rw) here to check
- # check_authn(user,pass) -> T/F
+ """
+ Validates that username/password are a valid combination, but does
+ not check access levels.
+ """
- apache.log_error("authenticate handler called")
+ my_pw = req.get_basic_auth_pw()
+ my_user = req.user
+ my_uri = req.uri
- if user == "admin" and pw == "cobbler":
- return apache.OK
- else:
+ apache.log_error("authenhandler called: %s" % my_user)
+ try:
+ token = xmlrpc_server.login(my_user,my_pw)
+ except:
return apache.HTTP_UNAUTHORIZED
-def accesshandler(req):
- uri = req.uri
+ try:
+ ok = xmlrpc_server.check_access(token,my_uri)
+ except:
+ return apache.HTTP_FORBIDDEN
+
- apache.log_error("accesshandler uri: %s" % (uri))
+ sess=__get_session(req)
+ sess['cobbler_token'] = token
+ sess.save()
- # FIXME: poll cobbler_api (not rw) here to check
- # check_access(user,uri) -> T/F
+ return apache.OK
+
+#======================================================
+
+def accesshandler(req):
+
+ """
+ Not using this
+ """
- if uri.find("hello") != -1:
- return apache.HTTP_FORBIDDEN
return apache.OK
+#======================================================
+
def authenzhandler(req):
- # we really don't need this because of the accesshandler.
- # add in later if we find we /DO/ need it
- return apache.OK
+ """
+ Not using this
+ """
+ return apache.OK