summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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