summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@redhat.com>2008-08-28 17:54:13 -0400
committerMichael DeHaan <mdehaan@redhat.com>2008-08-28 17:54:13 -0400
commitf2406b0115acd0c2a34ac27f572037e02c54ddd8 (patch)
treecd641a80b5bdb45e01eb1ac2da6c35f72a8c29b5
parentc3cb47903f10493d78fa575db1a085e3091ad84b (diff)
downloadcobbler-f2406b0115acd0c2a34ac27f572037e02c54ddd8.tar.gz
cobbler-f2406b0115acd0c2a34ac27f572037e02c54ddd8.tar.xz
cobbler-f2406b0115acd0c2a34ac27f572037e02c54ddd8.zip
Lots of work on the acl module, still need to test some niche cases and ensure
the authz_configfile still works, though ownership is looking pretty good at this point with ACL's tacked on after normal authz approval
-rw-r--r--MANIFEST.in1
-rw-r--r--Makefile2
-rw-r--r--cobbler.spec1
-rw-r--r--cobbler/api.py6
-rw-r--r--cobbler/modules/authz_allowall.py2
-rw-r--r--cobbler/modules/authz_configfile.py5
-rw-r--r--cobbler/modules/authz_ownership.py76
-rw-r--r--cobbler/remote.py6
-rw-r--r--config/acls.conf110
-rw-r--r--config/modules.conf25
-rw-r--r--setup.py1
11 files changed, 120 insertions, 115 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index ab952513..659f04a2 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,7 @@
include loaders/COPYING_ELILO
include loaders/elilo-3.6-ia64.efi
include loaders/menu.c32
+include config/acls.conf
include config/cobbler.conf
include config/cobbler_svc.conf
include config/rsync.exclude
diff --git a/Makefile b/Makefile
index 8fad1227..18652e78 100644
--- a/Makefile
+++ b/Makefile
@@ -39,12 +39,14 @@ devinstall:
-cp /etc/cobbler/settings /tmp/cobbler_settings
-cp /etc/cobbler/modules.conf /tmp/cobbler_modules.conf
-cp /etc/httpd/conf.d/cobbler.conf /tmp/cobbler_http.conf
+ -cp /etc/cobbler/acls.conf /tmp/cobbler_acls.conf
-cp /etc/cobbler/users.conf /tmp/cobbler_users.conf
-cp /etc/cobbler/users.digest /tmp/cobbler_users.digest
make install
-cp /tmp/cobbler_settings /etc/cobbler/settings
-cp /tmp/cobbler_modules.conf /etc/cobbler/modules.conf
-cp /tmp/cobbler_users.conf /etc/cobbler/users.conf
+ -cp /tmp/cobbler_acls.conf /etc/cobbler/acls.conf
-cp /tmp/cobbler_users.digest /etc/cobbler/users.digest
-cp /tmp/cobbler_http.conf /etc/httpd/conf.d/cobbler.conf
find /var/lib/cobbler/triggers | xargs chmod +x
diff --git a/cobbler.spec b/cobbler.spec
index f8588edc..faca0e11 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -130,6 +130,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%config(noreplace) /etc/logrotate.d/cobblerd_rotate
%config(noreplace) /etc/cobbler/modules.conf
%config(noreplace) /etc/cobbler/users.conf
+%config(noreplace) /etc/cobbler/acls.conf
%dir %{python_sitelib}/cobbler
%dir %{python_sitelib}/cobbler/yaml
%dir %{python_sitelib}/cobbler/modules
diff --git a/cobbler/api.py b/cobbler/api.py
index b78d8cf7..3defb05f 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -38,6 +38,7 @@ import sub_process
import module_loader
import kickgen
import yumgen
+import acls
import logging
import os
@@ -89,6 +90,8 @@ class BootAPI:
self._config = config.Config(self)
self.deserialize()
+ self.acl_engine = acls.AclEngine()
+
self.authn = self.get_module_from_file(
"authentication",
"module",
@@ -492,8 +495,9 @@ class BootAPI:
"""
(Remote) access control.
"""
- rc = self.authz.authorize(self,user,resource,arg1,arg2)
+ rc = self.authz.authorize(self,user,resource,arg1,arg2,self.acl_engine)
self.log("authorize",[user,resource,arg1,arg2,rc],debug=True)
+ # if we clear authz, now ask the ACL engine
return rc
def build_iso(self,iso=None,profiles=None,systems=None,tempdir=None):
diff --git a/cobbler/modules/authz_allowall.py b/cobbler/modules/authz_allowall.py
index 890f144f..9367c607 100644
--- a/cobbler/modules/authz_allowall.py
+++ b/cobbler/modules/authz_allowall.py
@@ -40,7 +40,7 @@ def register():
"""
return "authz"
-def authorize(api_handle,user,resource,arg1=None,arg2=None):
+def authorize(api_handle,user,resource,arg1=None,arg2=None,acl_engine=None):
"""
Validate a user against a resource.
"""
diff --git a/cobbler/modules/authz_configfile.py b/cobbler/modules/authz_configfile.py
index ddb02242..748ad7c6 100644
--- a/cobbler/modules/authz_configfile.py
+++ b/cobbler/modules/authz_configfile.py
@@ -47,8 +47,7 @@ def __parse_config():
alldata[g][o] = 1
return alldata
-
-def authorize(api_handle,user,resource,arg1=None,arg2=None):
+def authorize(api_handle,user,resource,arg1=None,arg2=None,acl_engine=None):
"""
Validate a user against a resource.
All users in the file are permitted by this module.
@@ -59,7 +58,7 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None):
data = __parse_config()
for g in data:
if user in data[g]:
- return 1
+ return acl_engine.can_access(g,user,resource,arg1,arg2)
return 0
if __name__ == "__main__":
diff --git a/cobbler/modules/authz_ownership.py b/cobbler/modules/authz_ownership.py
index aed9cd66..ecef5516 100644
--- a/cobbler/modules/authz_ownership.py
+++ b/cobbler/modules/authz_ownership.py
@@ -58,7 +58,7 @@ def __parse_config():
alldata[g][o] = 1
return alldata
-def __authorize_kickstart(api_handle, user, user_groups, kickstart):
+def __authorize_kickstart(api_handle, group, user, kickstart, resource, arg1, arg2, acl_engine):
# the authorization rules for kickstart editing are a bit
# of a special case. Non-admin users can edit a kickstart
# only if all objects that depend on that kickstart are
@@ -80,27 +80,29 @@ def __authorize_kickstart(api_handle, user, user_groups, kickstart):
lst = api_handle.find_profile(kickstart=kickstart, return_list=True)
lst.extend(api_handle.find_system(kickstart=kickstart, return_list=True))
for obj in lst:
- if not __is_user_allowed(obj, user, user_groups):
+ if not __is_user_allowed(obj, group, user, resource, arg1, arg2, acl_engine):
return 0
return 1
-def __is_user_allowed(obj, user, user_groups):
+def __is_user_allowed(obj, group, user, resource, arg1, arg2, acl_engine):
if obj.owners == []:
# no ownership restrictions, cleared
- return 1
+ print "DEBUG: check Z1"
+ return acl_engine.can_access(group, user, resource, arg1, arg2)
for allowed in obj.owners:
if user == allowed:
# user match
- return 1
+ print "DEBUG: check Z2"
+ return acl_engine.can_access(group, user, resource, arg1, arg2)
# else look for a group match
- for group in user_groups:
- if group == allowed and user in user_groups[group]:
- return 1
+ if group == allowed:
+ print "DEBUG: check Z3"
+ return acl_engine.can_access(group, user, resource, arg1, arg2)
return 0
-def authorize(api_handle,user,resource,arg1=None,arg2=None):
+def authorize(api_handle,user,resource,arg1=None,arg2=None,acl_engine=None):
"""
Validate a user against a resource.
All users in the file are permitted by this module.
@@ -111,15 +113,17 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None):
# everybody can get read-only access to everything
# if they pass authorization, they don't have to be in users.conf
if resource is not None:
+ # FIXME: /cobbler/web should not be subject to user check in any case
for x in [ "get", "read", "/cobbler/web" ]:
if resource.startswith(x):
- return 1
+ print "- DEBUG: get/read/other always ok"
+ return 1 # read operation is always ok.
user_groups = __parse_config()
# classify the type of operation
modify_operation = False
- for criteria in ["save","remove","modify","write","edit"]:
+ for criteria in ["save","copy","rename","remove","modify","write","edit"]:
if resource.find(criteria) != -1:
modify_operation = True
@@ -127,14 +131,18 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None):
# FIXME: deal with the problem of deleted parents and promotion
found_user = False
- for g in user_groups:
+ found_group = None
+ grouplist = user_groups.keys()
+ for g in grouplist:
for x in user_groups[g]:
if x == user:
+ found_group = g
found_user = True
# if user is in the admin group, always authorize
# regardless of the ownership of the object.
if g == "admins" or g == "admin":
- return 1
+ print "DEBUG: check A"
+ return acl_engine.can_access(found_group,user,resource,arg1,arg2)
break
if not found_user:
@@ -144,7 +152,8 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None):
if not modify_operation:
# sufficient to allow access for non save/remove ops to all
# users for now, may want to refine later.
- return 1
+ print "DEBUG: check B"
+ return acl_engine.can_access(found_group,user,resource,arg1,arg2)
# now we have a modify_operation op, so we must check ownership
# of the object. remove ops pass in arg1 as a string name,
@@ -153,9 +162,11 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None):
# function, rather than going through the rest of the code here.
if resource.find("write_kickstart") != -1:
+ print "DEBUG: check C"
return __authorize_kickstart(api_handle,user,user_groups,arg1)
elif resource.find("read_kickstart") != -1:
- return True
+ print "DEBUG: check D"
+ return acl_engine.can_access(found_group,user,resource,arg1,arg2)
obj = None
if resource.find("remove") != -1:
@@ -172,19 +183,40 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None):
# if the object has no ownership data, allow access regardless
if obj.owners is None or obj.owners == []:
- return 1
+ print "DEBUG: check E"
+ return acl_engine.can_access(found_group,user,resource,arg1,arg2)
- return __is_user_allowed(obj,user,user_groups)
+ print "DEBUG: check F"
+ return __is_user_allowed(obj,found_group,user,resource,arg1,arg2,acl_engine)
if __name__ == "__main__":
# real tests are contained in tests/tests.py
import api as cobbler_api
+ import acls
+ acl_engine = acls.AclEngine()
api = cobbler_api.BootAPI()
print __parse_config()
- print authorize(api, "admin1", "sync")
- d = api.find_distro("F9B-i386")
- d.set_owners(["allowed"])
+ print authorize(api, "testing", "sync", acl_engine=acl_engine)
+ d = api.find_distro("F9I-i386")
+ d.set_owners(["jradmin"])
api.add_distro(d)
- print authorize(api, "admin1", "save_distro", d)
- print authorize(api, "basement2", "save_distro", d)
+ p = api.find_profile("F9I-i386")
+ p.set_owners(["jradmin"])
+ api.add_profile(p)
+ s = api.find_system("foo")
+ s.set_owners(["jradmin"])
+ api.add_system(s)
+ print "**** TRY SOMETHING I CAN'T DO"
+ print authorize(api, "testing", "save_profile", p, acl_engine=acl_engine)
+ print "**** TRY SOMETHING I CAN'T DO"
+ print authorize(api, "testing", "save_distro", d, acl_engine=acl_engine)
+ print "***** EDIT SYSTEM I OWN"
+ print authorize(api, "testing", "save_system", s, acl_engine=acl_engine)
+ s = api.find_system("foo")
+ s.set_owners("notyou")
+ api.add_system(s)
+ print "***** EDIT SYSTEM I DONT OWN"
+ print authorize(api, "testing", "save_system", s, acl_engine=acl_engine)
+
+
diff --git a/cobbler/remote.py b/cobbler/remote.py
index cb9e51f3..8b6ea3d9 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -1138,7 +1138,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
existing system object handle.
"""
obj = self.__get_object(object_id)
- self.check_access(token, "modify_system", obj, attribute)
+ self.check_access(token, "modify_system", obj, attribute, arg)
return self.__call_method(obj, attribute, arg)
def modify_repo(self,object_id,attribute,arg,token):
@@ -1224,9 +1224,9 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
if is_read:
- what = "read_kickstart_template":
+ what = "read_kickstart_template"
else:
- what = "write_kickstart_template":
+ what = "write_kickstart_template"
self.log(what,name=kickstart_file,token=token)
self.check_access(token,what,kickstart_file,is_read)
diff --git a/config/acls.conf b/config/acls.conf
index 09b82a71..be0caed0 100644
--- a/config/acls.conf
+++ b/config/acls.conf
@@ -1,66 +1,48 @@
-# the acls.conf file lists specific custom operations to deny to users of certain groups
-# when using the authz_configfile or authz_ownership modules.
-#
-# the denial control flow is:
-#
-# Authentication module -> Authorization module -> ACL list
-
-
-# Deny nothing from users in the "admin" or "admins" groups
-
-admin: ~
-admins: ~
-
-# Deny nothing from users whose groups are not found in this file:
-
-unmatched: ~
-
-# Example1: users in the group "jradmin" can create/edit/modify systems as long as
-# the authorization module lets them. However they do not have permission to create
-# new distributions, profiles, image records, or repos. The authorization modules chosen
-# in /etc/cobbler/modules.conf are responsible for chosing the group mapping.
-
+---
+admin: {}
+admins: {}
jradmin:
- "new_distro": ~
- "new_profile": ~
- "new_image": ~
- "new_repo": ~
- "copy_distro": ~
- "copy_profile": ~
- "copy_image": ~
- "copy_repo": ~
- "remove_distro": ~
- "remove_profile": ~
- "remove_image": ~
- "remove_repo": ~
- "modify_distro": ~
- "modify_profile": ~
- "modify_image": ~
- "modify_repo": ~
- "write_kickstart_templates" : ~
-
-# Example2: users in group "less trusted" can only modify existing systems that some one
-# else creates. If the ownership module is in use, they must also be in the ownership list
-# in addition, they cannot manipulate network details of the systems they own.
-
+ copy_distro: {}
+ copy_image: {}
+ copy_profile: {}
+ copy_repo: {}
+ modify_distro: {}
+ modify_image: {}
+ modify_profile: {}
+ modify_repo: {}
+ new_distro: {}
+ new_image: {}
+ new_profile: {}
+ new_repo: {}
+ remove_distro: {}
+ remove_image: {}
+ remove_profile: {}
+ remove_repo: {}
+ save_distro: {}
+ save_profile: {}
+ save_image: {}
+ save_repo: {}
+ write_kickstart_templates: {}
lesstrusted:
- "new_*": ~
- "copy_*": ~
- "remove_*": ~
- "modify_distro": ~
- "modify_profile": ~
- "modify_image": ~
- "modify_repo": ~
- "modify_system":
- - "mac-address-*"
- - "ip-address-*"
- - "hostname-*"
- - "gateway-*"
- - "subnet-*"
- "save_distro": ~
- "save_profile": ~
- "save_image": ~
- "save_repo": ~
- "rename_*": ~
- "sync" : ~
- "write_kickstart_templates" : ~
+ copy_*: {}
+ modify_distro: {}
+ modify_image: {}
+ modify_profile: {}
+ modify_repo: {}
+ modify_system:
+ gateway-*: {}
+ hostname-*: {}
+ ip-address-*: {}
+ mac-address-*: {}
+ subnet-*: {}
+ new_*: {}
+ remove_*: {}
+ rename_*: {}
+ save_distro: {}
+ save_image: {}
+ save_profile: {}
+ save_repo: {}
+ sync: {}
+ write_kickstart_templates: {}
+unmatched: {}
+
diff --git a/config/modules.conf b/config/modules.conf
index 6b57d62b..9a483255 100644
--- a/config/modules.conf
+++ b/config/modules.conf
@@ -52,6 +52,10 @@ module = authn_denyall
#
# WARNING: this is a security setting, do not choose an option blindly.
#
+# For modules above that have a concept of groups, /etc/cobbler/acls.conf
+# will be enforced after this module is applied. For those that do not
+# have a concept of groups (authz_allowall) it will be ignored.
+#
# for more information:
# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface
# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity
@@ -91,24 +95,3 @@ module = manage_bind
[dhcp]
module = manage_isc
-# configures where ACL data is sourced from. access control
-# lists govern what remote features a user can acess based
-# on their username or group membership information.
-#
-# Note that usage of ACLs requires a choice of an authorization module
-# that supports ACLs. authz_ownership is one example. An authorization
-# module may refuse access based on other critiera /prior/ to consulting
-# the access control list. Usage of ACLs with an authorzation module that
-# does not support ACLs will have no effect.
-#
-# choices:
-# acls_none -- returns a default ACL list allows all actions
-# provided the authorization module does not
-# reject access for other reasons (such as ownership)
-# acls_configfile -- sources ACL information from /etc/cobbler/acls.conf
-# further configuration is required in /etc/cobbler/acls.conf
-
-[acls]
-module = acls_none
-
-
diff --git a/setup.py b/setup.py
index 01fa7c9d..c0feebfd 100644
--- a/setup.py
+++ b/setup.py
@@ -79,6 +79,7 @@ if __name__ == "__main__":
(etcpath, ['config/users.digest']),
(etcpath, ['config/rsync.exclude']),
(etcpath, ['config/users.conf']),
+ (etcpath, ['config/acls.conf']),
(initpath, ['config/cobblerd']),
(etcpath, ['config/settings']),
# (bashpath, ['config/cobbler_bash']),