summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@redhat.com>2007-12-05 18:59:24 -0500
committerMichael DeHaan <mdehaan@redhat.com>2007-12-05 18:59:24 -0500
commit0805e18d1e4077605b382acb9322996a90782c4d (patch)
tree098ba9d7b7655a910d69e6ea692b7a05fad79139
parent6bd19ac076e5d4c51317d85fd5d12965e65cae66 (diff)
downloadthird_party-cobbler-0805e18d1e4077605b382acb9322996a90782c4d.zip
third_party-cobbler-0805e18d1e4077605b382acb9322996a90782c4d.tar.gz
third_party-cobbler-0805e18d1e4077605b382acb9322996a90782c4d.tar.xz
Some initial work on kerberos authentication via a helper program, some work on making the API have access to the log files and logging everything done there. The logging work, as well as kerb testing, are incomplete at this point, though
authn_configfile works fine.
-rw-r--r--MANIFEST.in1
-rw-r--r--cobbler.spec1
-rw-r--r--cobbler/api.py56
-rw-r--r--cobbler/modules/authn_configfile.py5
-rw-r--r--cobbler/modules/authn_kerberos.py81
-rw-r--r--cobbler/modules/authz_allowall.py2
-rw-r--r--cobbler/remote.py27
-rw-r--r--cobbler/settings.py1
-rw-r--r--config/cobblerd_rotate10
-rw-r--r--config/settings1
-rw-r--r--scripts/cobbler_auth_help54
-rw-r--r--setup.py2
12 files changed, 214 insertions, 27 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 58a1df9..357cdcc 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -24,6 +24,7 @@ include scripts/nopxe.cgi
include scripts/webui.cgi
include scripts/gateway.py
include scripts/post_install_trigger.cgi
+include scripts/cobbler_auth_help
include snippets/*
recursive-include po *.pot
recursive-include po *.po
diff --git a/cobbler.spec b/cobbler.spec
index 77a246f..afb3db6 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -114,6 +114,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%dir /tftpboot/images
%{_bindir}/cobbler
%{_bindir}/cobblerd
+%{_bindir}/cobbler_auth_help
%dir /etc/cobbler
%config(noreplace) /etc/cobbler/default.ks
%config(noreplace) /etc/cobbler/kickstart_fc5.ks
diff --git a/cobbler/api.py b/cobbler/api.py
index e6ef88b..6343035 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -24,6 +24,11 @@ import action_status
import action_validate
import sub_process
import module_loader
+import logging
+
+ERROR = 100
+INFO = 10
+DEBUG = 5
class BootAPI:
@@ -37,10 +42,33 @@ class BootAPI:
self.__dict__ = self.__shared_state
if not BootAPI.has_loaded:
+
+
+ logger = logging.getLogger("cobbler.api")
+ logger.setLevel(logging.DEBUG)
+ ch = logging.FileHandler("/var/log/cobbler/cobbler.log")
+ ch.setLevel(logging.DEBUG)
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
+ ch.setFormatter(formatter)
+ logger.addHandler(ch)
+
BootAPI.has_loaded = True
module_loader.load_modules()
self._config = config.Config(self)
self.deserialize()
+ self.logger = logger
+ self.logger.debug("API handle initialized")
+
+ self.authn = self.get_module_from_file(
+ "authentication",
+ "module",
+ "authn_configfile"
+ )
+ self.authz = self.get_module_from_file(
+ "authorization",
+ "module",
+ "authz_allowall"
+ )
def version(self):
"""
@@ -48,6 +76,7 @@ class BootAPI:
Currently checks the RPM DB, which is not perfect.
Will return "?" if not installed.
"""
+ self.logger.debug("cobbler version")
cmd = sub_process.Popen("/bin/rpm -q cobbler", stdout=sub_process.PIPE, shell=True)
result = cmd.communicate()[0].replace("cobbler-","")
if result.find("not installed") != -1:
@@ -55,7 +84,6 @@ class BootAPI:
tokens = result[:result.rfind("-")].split(".")
return int(tokens[0]) + 0.1 * int(tokens[1]) + 0.001 * int(tokens[2])
-
def clear(self):
"""
Forget about current list of profiles, distros, and systems
@@ -99,12 +127,14 @@ class BootAPI:
"""
Return a blank, unconfigured system, unattached to a collection
"""
+ self.logger.debug("new_system")
return self._config.new_system(is_subobject=is_subobject)
def new_distro(self,is_subobject=False):
"""
Create a blank, unconfigured distro, unattached to a collection.
"""
+ self.logger.debug("new_distro")
return self._config.new_distro(is_subobject=is_subobject)
@@ -112,12 +142,14 @@ class BootAPI:
"""
Create a blank, unconfigured profile, unattached to a collection
"""
+ self.logger.debug("new_profile")
return self._config.new_profile(is_subobject=is_subobject)
def new_repo(self,is_subobject=False):
"""
Create a blank, unconfigured repo, unattached to a collection
"""
+ self.logger.debug("new_repo")
return self._config.new_repo(is_subobject=is_subobject)
def auto_add_repos(self):
@@ -125,6 +157,7 @@ class BootAPI:
Import any repos this server knows about and mirror them.
Credit: Seth Vidal.
"""
+ self.logger.debug("auto_add_repos")
try:
import yum
except:
@@ -164,6 +197,7 @@ class BootAPI:
for human admins, who may, for instance, forget to properly set up
their TFTP servers for PXE, etc.
"""
+ self.logger.debug("check")
check = action_check.BootCheck(self._config)
return check.run()
@@ -176,6 +210,7 @@ class BootAPI:
is not available on all platforms and can not detect "future"
kickstart format correctness.
"""
+ self.logger.debug("validateks")
validator = action_validate.Validate(self._config)
return validator.run()
@@ -186,6 +221,7 @@ class BootAPI:
/tftpboot. Any operations done in the API that have not been
saved with serialize() will NOT be synchronized with this command.
"""
+ self.logger.debug("sync")
sync = action_sync.BootSync(self._config)
return sync.run()
@@ -194,10 +230,12 @@ class BootAPI:
Take the contents of /var/lib/cobbler/repos and update them --
or create the initial copy if no contents exist yet.
"""
+ self.logger.debug("reposync")
reposync = action_reposync.RepoSync(self._config)
return reposync.run(name)
def status(self,mode):
+ self.logger.debug("status")
statusifier = action_status.BootStatusReport(self._config, mode)
return statusifier.run()
@@ -252,4 +290,20 @@ class BootAPI:
"""
return module_loader.get_modules_in_category(category)
+ def authenticate(self,user,password):
+ """
+ (Remote) access control.
+ """
+ self.logger.debug("authorize(%s)" % (user))
+ rc = self.authn.authenticate(self,user,password)
+ self.logger.debug("authorize(%s)=%s" % (user,rc))
+ return rc
+
+ def authorize(self,user,resource,arg1=None,arg2=None):
+ """
+ (Remote) access control.
+ """
+ rc = self.authz.authorize(self,user,resource,arg1,arg2)
+ self.logger.debug("authorize(%s,%s)=%s" % (user,resource,rc))
+ return rc
diff --git a/cobbler/modules/authn_configfile.py b/cobbler/modules/authn_configfile.py
index 5740efa..30637b7 100644
--- a/cobbler/modules/authn_configfile.py
+++ b/cobbler/modules/authn_configfile.py
@@ -52,7 +52,7 @@ def __parse_storage():
pass
return results
-def authenticate(username,password):
+def authenticate(api_handle,username,password):
"""
Validate a username/password combo, returning True/False
@@ -70,7 +70,4 @@ def authenticate(username,password):
return False
-if __name__ == "__main__":
- print authenticate("cobbler","cobbler")
- print authenticate("cobbler","bogus")
diff --git a/cobbler/modules/authn_kerberos.py b/cobbler/modules/authn_kerberos.py
new file mode 100644
index 0000000..7f85db6
--- /dev/null
+++ b/cobbler/modules/authn_kerberos.py
@@ -0,0 +1,81 @@
+"""
+Authentication module that uses kerberos.
+
+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.
+"""
+
+# NOTE: this is not using 'straight up' kerberos in that we
+# relay passwords through cobblerd for authentication, that may
+# be done later. It does of course check against kerberos,
+# however.
+
+# ALSO NOTE: we're calling out to a Perl program to make
+# this work. You must install Authen::Simple::Kerberos
+# from CPAN and the Kerberos libraries for this to work.
+# See the Cobbler Wiki for more info.
+
+# ALSO ALSO NOTE: set kerberos_realm in /var/lib/cobbler/settings
+# to something appropriate or this will never work. CASING
+# MATTERS. example.com != EXAMPLE.COM.
+
+import distutils.sysconfig
+import ConfigParser
+import sys
+import os
+from rhpl.translate import _, N_, textdomain, utf8
+import md5
+import traceback
+# since sub_process isn't available on older OS's
+try:
+ import sub_process as subprocess
+except:
+ import subprocess
+
+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(api_handle,username,password):
+ """
+ Validate a username/password combo, returning True/False
+ Uses cobbler_auth_helper
+ """
+
+ realm = self.api.settings().kerberos_realm
+ api_handle.logger.debug("authenticating %s against %s" % (username,realm))
+
+ rc = subprocess.call([
+ "/usr/bin/cobbler_auth_help",
+ "--method=kerberos",
+ "--username=%s" % username,
+ "--password=%s" % password,
+ "--realm=%s" % realm
+ ])
+ print rc
+ if rc == 42:
+ api_handle.logger.debug("authenticated ok")
+ # authentication ok (FIXME: log)
+ return True
+ else:
+ api_handle.logger.debug("authentication failed")
+ # authentication failed
+ return False
+
+
diff --git a/cobbler/modules/authz_allowall.py b/cobbler/modules/authz_allowall.py
index 4125ed6..1b05630 100644
--- a/cobbler/modules/authz_allowall.py
+++ b/cobbler/modules/authz_allowall.py
@@ -32,7 +32,7 @@ def register():
"""
return "authz"
-def authorize(user,resource,arg1=None,arg2=None):
+def authorize(api_handle,user,resource,arg1=None,arg2=None):
"""
Validate a user against a resource.
"""
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 081f8c8..e84827a 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -20,7 +20,6 @@ import os
import SimpleXMLRPCServer
from rhpl.translate import _, N_, textdomain, utf8
import xmlrpclib
-import logging
import random
import base64
@@ -52,7 +51,7 @@ class CobblerXMLRPCInterface:
def __init__(self,api,logger):
self.api = api
- self.logger = logger
+ self.logger = self.api.logger
def __sorter(self,a,b):
return cmp(a["name"],b["name"])
@@ -365,17 +364,6 @@ 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):
"""
@@ -435,7 +423,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.
"""
- return self.authn.authenticate(input_user,input_password)
+ return self.api.authenticate(input_user,input_password)
def __validate_token(self,token):
"""
@@ -457,6 +445,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
raise CX(_("invalid token: %s" % token))
def check_access(self,token,resource,arg1=None,arg2=None):
+ self.logger.debug("check_access(%s, %s)" % (token,resource))
validated = self.__validate_token(token)
return self.__authorize(token,resource,arg1,arg2)
@@ -473,17 +462,18 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
method calls. The token will time out after a set interval if not
used. Re-logging in permitted.
"""
+ self.logger.debug("login (%s)" % login_user)
if self.__validate_user(login_user,login_password):
token = self.__make_token(login_user)
- self.logger.info("login succeeded: %s" % login_user)
+ self.logger.debug("login succeeded: %s" % login_user)
return token
else:
- self.logger.info("login failed: %s" % login_user)
+ self.logger.debug("login failed: %s" % login_user)
raise CX(_("login failed: %s") % login_user)
def __authorize(self,token,resource,arg1=None,arg2=None):
user = self.__get_user_from_token(token)
- if self.authz.authorize(user,resource,arg1,arg2):
+ if self.api.authorize(user,resource,arg1,arg2):
return True
else:
raise CX(_("user does not have access to resource: %s") % resource)
@@ -492,6 +482,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
Retires a token ahead of the timeout.
"""
+ self.logger.debug("logout(%s)" % token)
if self.token_cache.has_key(token):
del self.token_cache[token]
return True
@@ -501,6 +492,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
This is a demo function that does not return anything useful.
"""
+ self.logger.debug("token_check(%s)" % token)
self.__validate_token(token)
return True
@@ -830,3 +822,4 @@ class CobblerReadWriteXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
self.allow_reuse_address = True
SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self,args)
+
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 8f9527d..c1fe232 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -34,6 +34,7 @@ DEFAULTS = {
"dnsmasq_bin" : "/usr/sbin/dnsmasq",
"dnsmasq_conf" : "/etc/dnsmasq.conf",
"httpd_bin" : "/usr/sbin/httpd",
+ "kerberos_realm" : "example.org",
"kernel_options" : {
"lang" : " ",
"text" : None,
diff --git a/config/cobblerd_rotate b/config/cobblerd_rotate
index 94fac8d..0e4bcbf 100644
--- a/config/cobblerd_rotate
+++ b/config/cobblerd_rotate
@@ -1,4 +1,4 @@
-/var/log/cobbler/cobblerd.log {
+/var/log/cobbler/cobbler.log {
missingok
notifempty
rotate 4
@@ -10,10 +10,14 @@
endscript
}
-/var/log/httpd/cobbler_wui.log {
+/var/log/cobbler/webui.log {
missingok
notifempty
rotate 4
weekly
+ postrotate
+ if [ -f /var/lock/subsys/cobblerd ]; then
+ /etc/init.d/cobblerd condrestart
+ fi
+ endscript
}
-
diff --git a/config/settings b/config/settings
index d47635a..f05c288 100644
--- a/config/settings
+++ b/config/settings
@@ -10,6 +10,7 @@ dhcpd_conf: /etc/dhcpd.conf
dnsmasq_bin: /usr/sbin/dnsmasq
dnsmasq_conf: /etc/dnsmasq.conf
httpd_bin: /usr/sbin/httpd
+kerberos_realm: 'example.org'
kernel_options:
ksdevice: eth0
lang: ' '
diff --git a/scripts/cobbler_auth_help b/scripts/cobbler_auth_help
new file mode 100644
index 0000000..12a38b0
--- /dev/null
+++ b/scripts/cobbler_auth_help
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+
+# Kerberos helper for logins
+#
+# 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.
+
+# Usage:
+# cobbler_auth_helper kerberos username pass
+# (may do other auth types later)
+# Returns:
+# 0 on ok, non-0 on failure
+# API info:
+# http://search.cpan.org/~chansen/Authen-Simple-Kerberos-0.1/
+
+use warnings;
+use strict;
+use Authen::Simple::Kerberos;
+use Getopt::Long;
+
+my $method;
+my $username;
+my $realm;
+my $password;
+my $verbose=0;
+
+my $result = GetOptions(
+ "method=s" => \$method,
+ "username=s" => \$username,
+ "realm=s" => \$realm,
+ "password=s" => \$password,
+);
+
+my $kerberos = Authen::Simple::Kerberos->new(
+ realm => $realm
+);
+
+print "authenticating: $username against $method $realm ($password)\n" if $verbose;
+
+if ( $kerberos->authenticate( $username, $password ) ) {
+ print "ok\n" if $verbose;
+ exit(42);
+}
+
+print "denied\n" if $verbose;
+exit(1);
+
diff --git a/setup.py b/setup.py
index e839fd6..75b06f0 100644
--- a/setup.py
+++ b/setup.py
@@ -59,7 +59,7 @@ if __name__ == "__main__":
"cobbler/modules",
"cobbler/webui",
],
- scripts = ["scripts/cobbler", "scripts/cobblerd"],
+ scripts = ["scripts/cobbler", "scripts/cobblerd", "scripts/cobbler_auth_help"],
data_files = [
(modpython, ['scripts/index.py']),
# cgi files