diff options
author | John Dennis <jdennis@redhat.com> | 2007-11-21 13:11:10 -0500 |
---|---|---|
committer | John Dennis <jdennis@redhat.com> | 2007-11-21 13:11:10 -0500 |
commit | d98686e96758870cb4a56d41fb0aaae54d4067c5 (patch) | |
tree | 6fc7101684591afdfb9677732352e59067066bc1 /ipa-server | |
parent | 087d11af5cebe7bb7a87d0581c7fa95353d9aa3b (diff) | |
download | freeipa-d98686e96758870cb4a56d41fb0aaae54d4067c5.tar.gz freeipa-d98686e96758870cb4a56d41fb0aaae54d4067c5.tar.xz freeipa-d98686e96758870cb4a56d41fb0aaae54d4067c5.zip |
Add radius profile implementations:
get_radius_profile_by_uid
add_radius_profile
update_radius_profile
delete_radius_profile
find_radius_profiles
Rewrite command line arg handling, now support pair entry, interactive
mode with auto completion, reading pairs from a file, better handling
of mandatory values, better help, long arg names now match attribute
name in pairs
Establish mappings for all attributes and names used in clients and
profiles
Add notion of containers to radius clients and profiles in LDAP
Move common code, variables, constants, and strings into the files
radius_client.py, radius_util.py, ipautil.py to eliminate redundant
elements which could get out of sync if modified and to provide access
to other code which might benefit from using these items in the
future.
Add utility functions:
format_list()
parse_key_value_pairs()
Add utility class:
AttributeValueCompleter
Unify attribute usage in radius ldap schema
Diffstat (limited to 'ipa-server')
-rw-r--r-- | ipa-server/ipa-install/share/60radius.ldif | 12 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/bootstrap-template.ldif | 4 | ||||
-rw-r--r-- | ipa-server/ipaserver/radiusinstance.py | 67 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/funcs.py | 155 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/ipaxmlrpc.py | 5 |
5 files changed, 155 insertions, 88 deletions
diff --git a/ipa-server/ipa-install/share/60radius.ldif b/ipa-server/ipa-install/share/60radius.ldif index 47692352..3562312a 100644 --- a/ipa-server/ipa-install/share/60radius.ldif +++ b/ipa-server/ipa-install/share/60radius.ldif @@ -492,7 +492,7 @@ objectClasses: NAME 'radiusprofile' SUP top AUXILIARY DESC '' - MUST cn + MUST uid MAY ( radiusArapFeatures $ radiusArapSecurity $ radiusArapZoneAccess $ radiusAuthType $ radiusCallbackId $ radiusCallbackNumber $ radiusCalledStationId $ radiusCallingStationId $ radiusClass $ @@ -527,14 +527,6 @@ objectClasses: MAY ( uid $ userPassword $ description ) ) attributeTypes: - ( 1.3.6.1.4.1.3317.4.3.1.63 - NAME 'radiusClientNASIpAddress' - DESC '' - EQUALITY caseIgnoreIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 - SINGLE-VALUE - ) -attributeTypes: ( 1.3.6.1.4.1.3317.4.3.1.64 NAME 'radiusClientSecret' DESC '' @@ -564,6 +556,6 @@ objectClasses: NAME 'radiusClientProfile' SUP top STRUCTURAL DESC 'A Container Objectclass to be used for describing radius clients' - MUST (radiusClientNASIpAddress $ radiusClientSecret) + MUST (radiusClientIPAddress $ radiusClientSecret) MAY ( radiusClientNASType $ radiusClientShortName $ description ) ) diff --git a/ipa-server/ipa-install/share/bootstrap-template.ldif b/ipa-server/ipa-install/share/bootstrap-template.ldif index fcc2506d..df59bc0e 100644 --- a/ipa-server/ipa-install/share/bootstrap-template.ldif +++ b/ipa-server/ipa-install/share/bootstrap-template.ldif @@ -92,11 +92,11 @@ objectClass: nsContainer objectClass: top cn: profiles -dn: cn=ipa_default, cn=profiles,cn=radius,cn=services,cn=etc,$SUFFIX +dn: uid=ipa_default, cn=profiles,cn=radius,cn=services,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: radiusprofile -cn: ipa_default +uid: ipa_default dn: cn=admins,cn=groups,cn=accounts,$SUFFIX changetype: add diff --git a/ipa-server/ipaserver/radiusinstance.py b/ipa-server/ipaserver/radiusinstance.py index 8317da03..0c94c713 100644 --- a/ipa-server/ipaserver/radiusinstance.py +++ b/ipa-server/ipaserver/radiusinstance.py @@ -26,6 +26,7 @@ import logging import pwd import time from ipa.ipautil import * +from ipa import radius_util import service @@ -33,18 +34,6 @@ import os import re IPA_RADIUS_VERSION = '0.0.0' -PKG_NAME = 'freeradius' -PKG_CONFIG_DIR = '/etc/raddb' - -RADIUS_SERVICE_NAME = 'radius' -RADIUS_USER = 'radiusd' - -IPA_KEYTAB_FILEPATH = os.path.join(PKG_CONFIG_DIR, 'ipa.keytab') -LDAP_ATTR_MAP_FILEPATH = os.path.join(PKG_CONFIG_DIR, 'ldap.attrmap') -RADIUSD_CONF_FILEPATH = os.path.join(PKG_CONFIG_DIR, 'radiusd.conf') -RADIUSD_CONF_TEMPLATE_FILEPATH = os.path.join(SHARE_DIR, 'radius.radiusd.conf.template') - -RADIUSD = '/usr/sbin/radiusd' # FIXME there should a utility to get the user base dn from ipaserver.funcs import DefaultUserContainer, DefaultGroupContainer @@ -58,7 +47,7 @@ def ldap_mod(fd, dn, pwd): def get_radius_version(): version = None try: - p = subprocess.Popen([RADIUSD, '-v'], stdout=subprocess.PIPE, + p = subprocess.Popen([radius_util.RADIUSD, '-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() status = p.returncode @@ -86,7 +75,7 @@ class RadiusInstance(service.Service): self.suffix = realm_to_suffix(self.realm) self.fqdn = host_name self.ldap_server = ldap_server - self.principal = "%s/%s@%s" % (RADIUS_SERVICE_NAME, self.fqdn, self.realm) + self.principal = "%s/%s@%s" % (radius_util.RADIUS_SERVICE_NAME, self.fqdn, self.realm) self.basedn = self.suffix self.user_basedn = "%s,%s" % (DefaultUserContainer, self.basedn) # FIXME, should be utility to get this self.radius_version = get_radius_version() @@ -117,34 +106,34 @@ class RadiusInstance(service.Service): version = 'IPA_RADIUS_VERSION=%s FREE_RADIUS_VERSION=%s' % (IPA_RADIUS_VERSION, self.radius_version) sub_dict = {'CONFIG_FILE_VERSION_INFO' : version, 'LDAP_SERVER' : self.ldap_server, - 'RADIUS_KEYTAB' : IPA_KEYTAB_FILEPATH, + 'RADIUS_KEYTAB' : radius_util.RADIUS_IPA_KEYTAB_FILEPATH, 'RADIUS_PRINCIPAL' : self.principal, 'RADIUS_USER_BASE_DN' : self.user_basedn, 'ACCESS_ATTRIBUTE' : '', 'ACCESS_ATTRIBUTE_DEFAULT' : 'TRUE', - 'CLIENTS_BASEDN' : 'cn=clients,cn=radius,cn=services,cn=etc,%s' % self.suffix, + 'CLIENTS_BASEDN' : radius_util.radius_clients_basedn(None, self.suffix), 'SUFFIX' : self.suffix, } try: - radiusd_conf = template_file(RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict) - radiusd_fd = open(RADIUSD_CONF_FILEPATH, 'w+') + radiusd_conf = template_file(radius_util.RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict) + radiusd_fd = open(radius_util.RADIUSD_CONF_FILEPATH, 'w+') radiusd_fd.write(radiusd_conf) radiusd_fd.close() except Exception, e: - logging.error("could not create %s: %s", RADIUSD_CONF_FILEPATH, e) + logging.error("could not create %s: %s", radius_util.RADIUSD_CONF_FILEPATH, e) def __create_radius_keytab(self): self.step("create radiusd keytab") try: - if file_exists(IPA_KEYTAB_FILEPATH): - os.remove(IPA_KEYTAB_FILEPATH) + if file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): + os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH) except os.error: - logging.error("Failed to remove %s", IPA_KEYTAB_FILEPATH) + logging.error("Failed to remove %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH) (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local") kwrite.write("addprinc -randkey %s\n" % (self.principal)) kwrite.flush() - kwrite.write("ktadd -k %s %s\n" % (IPA_KEYTAB_FILEPATH, self.principal)) + kwrite.write("ktadd -k %s %s\n" % (radius_util.RADIUS_IPA_KEYTAB_FILEPATH, self.principal)) kwrite.flush() kwrite.close() kread.close() @@ -152,7 +141,7 @@ class RadiusInstance(service.Service): # give kadmin time to actually write the file before we go on retry = 0 - while not file_exists(IPA_KEYTAB_FILEPATH): + while not file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): time.sleep(1) retry += 1 if retry > 15: @@ -160,10 +149,10 @@ class RadiusInstance(service.Service): os.exit() try: - pent = pwd.getpwnam(RADIUS_USER) - os.chown(IPA_KEYTAB_FILEPATH, pent.pw_uid, pent.pw_gid) + pent = pwd.getpwnam(radius_util.RADIUS_USER) + os.chown(radius_util.RADIUS_IPA_KEYTAB_FILEPATH, pent.pw_uid, pent.pw_gid) except Exception, e: - logging.error("could not chown on %s to %s: %s", IPA_KEYTAB_FILEPATH, RADIUS_USER, e) + logging.error("could not chown on %s to %s: %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH, radius_util.RADIUS_USER, e) #FIXME, should use IPAdmin method def __set_ldap_encrypted_attributes(self): @@ -179,27 +168,3 @@ class RadiusInstance(service.Service): #------------------------------------------------------------------------------- -# FIXME: this should be in a common area so it can be shared -def get_ldap_attr_translations(): - comment_re = re.compile('#.*$') - radius_attr_to_ldap_attr = {} - ldap_attr_to_radius_attr = {} - try: - f = open(LDAP_ATTR_MAP_FILEPATH) - for line in f.readlines(): - line = comment_re.sub('', line).strip() - if not line: continue - attr_type, radius_attr, ldap_attr = line.split() - print 'type="%s" radius="%s" ldap="%s"' % (attr_type, radius_attr, ldap_attr) - radius_attr_to_ldap_attr[radius_attr] = {'ldap_attr':ldap_attr, 'attr_type':attr_type} - ldap_attr_to_radius_attr[ldap_attr] = {'radius_attr':radius_attr, 'attr_type':attr_type} - f.close() - except Exception, e: - logging.error('cold not read radius ldap attribute map file (%s): %s', LDAP_ATTR_MAP_FILEPATH, e) - pass # FIXME - - #for k,v in radius_attr_to_ldap_attr.items(): - # print '%s --> %s' % (k,v) - #for k,v in ldap_attr_to_radius_attr.items(): - # print '%s --> %s' % (k,v) - diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py index 26fdba48..aa557f79 100644 --- a/ipa-server/xmlrpc-server/funcs.py +++ b/ipa-server/xmlrpc-server/funcs.py @@ -30,6 +30,7 @@ import xmlrpclib import copy import attrs from ipa import ipaerror +from ipa import radius_util import string from types import * @@ -458,41 +459,40 @@ class IPAServer: # radius support - # FIXME, why not just use get_entry_by_dn? - def get_radius_client_by_ip_addr(self, ip_addr, sattrs=None, opts=None): - ip_addr = self.__safe_filter(ip_addr) - basedn = 'cn=clients,cn=radius,cn=services,cn=etc,%s' % self.basedn # FIXME, should not be hardcoded - filter = "(&(radiusClientNASIpAddress=%s)(objectclass=radiusClientProfile))" % ip_addr + # clients + def get_radius_client_by_ip_addr(self, ip_addr, container=None, sattrs=None, opts=None): + filter = radius_util.radius_client_filter(ip_addr) + basedn = radius_util.radius_clients_basedn(container, self.basedn) return self.__get_sub_entry(basedn, filter, sattrs, opts) - def __is_radius_client_unique(self, ip_addr, opts): - """Return 1 if the radius client is unique in the tree, 0 otherwise.""" - ip_addr = self.__safe_filter(ip_addr) - basedn = 'cn=clients,cn=radius,cn=services,cn=etc,%s' % self.basedn # FIXME, should not be hardcoded - filter = "(&(radiusClientNASIpAddress=%s)(objectclass=radiusClientProfile))" % ip_addr + def __radius_client_exists(self, ip_addr, container, opts): + filter = radius_util.radius_client_filter(ip_addr) + basedn = radius_util.radius_clients_basedn(container, self.basedn) try: entry = self.__get_sub_entry(basedn, filter, ['dn','uid'], opts) - return 0 + return True except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - return 1 + return False - def add_radius_client (self, client, opts=None): - client_container = 'cn=clients,cn=radius,cn=services,cn=etc' # FIXME, should not be hardcoded - if self.__is_radius_client_unique(client['radiusClientNASIpAddress'], opts) == 0: - raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) + def add_radius_client (self, client, container=None, opts=None): + if container is None: + container = radius_util.clients_container - dn="radiusClientNASIpAddress=%s,%s,%s" % (ldap.dn.escape_dn_chars(client['radiusClientNASIpAddress']), - client_container,self.basedn) + ip_addr = client['radiusClientIPAddress'] + + if self.__radius_client_exists(ip_addr, container, opts): + raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) + dn = radius_util.radius_client_dn(ip_addr, container, self.basedn) entry = ipaserver.ipaldap.Entry(dn) # some required objectclasses entry.setValues('objectClass', 'top', 'radiusClientProfile') # fill in our new entry with everything sent by the client - for u in client: - entry.setValues(u, client[u]) + for attr in client: + entry.setValues(attr, client[attr]) conn = self.getConnection(opts) try: @@ -504,8 +504,8 @@ class IPAServer: def update_radius_client(self, oldentry, newentry, opts=None): return self.update_entry(oldentry, newentry, opts) - def delete_radius_client(self, ip_addr, opts=None): - client = self.get_radius_client_by_ip_addr(ip_addr, ['dn', 'cn'], opts) + def delete_radius_client(self, ip_addr, container=None, opts=None): + client = self.get_radius_client_by_ip_addr(ip_addr, container, ['dn', 'cn'], opts) if client is None: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) @@ -516,7 +516,7 @@ class IPAServer: self.releaseConnection(conn) return res - def find_radius_clients(self, ip_attrs, sattrs=None, searchlimit=0, timelimit=-1, opts=None): + def find_radius_clients(self, ip_attrs, container=None, sattrs=None, searchlimit=0, timelimit=-1, opts=None): def gen_filter(objectclass, attr, values): '''Given ('myclass', 'myattr', [v1, v2]) returns (&(objectclass=myclass)(|(myattr=v1)(myattr=v2))) @@ -527,8 +527,8 @@ class IPAServer: filter = "(&(objectclass=%s)(|%s))" % (objectclass, attrs) return filter - basedn = 'cn=clients,cn=radius,cn=services,cn=etc,%s' % self.basedn # FIXME, should not be hardcoded - filter = gen_filter('radiusClientProfile', 'radiusClientNASIpAddress', ip_attrs) + basedn = radius_util.radius_clients_basedn(container, self.basedn) + filter = gen_filter('radiusClientProfile', 'radiusClientIPAddress', ip_attrs) conn = self.getConnection(opts) try: try: @@ -546,6 +546,111 @@ class IPAServer: return radius_clients + # profiles + def get_radius_profile_by_uid(self, uid, user_profile=True, sattrs=None, opts=None): + if user_profile: + container = DefaultUserContainer + else: + container = radius_util.profiles_container + + uid = self.__safe_filter(uid) + filter = radius_util.radius_profile_filter(uid) + basedn = radius_util.radius_profiles_basedn(container, self.basedn) + return self.__get_sub_entry(basedn, filter, sattrs, opts) + + def __radius_profile_exists(self, uid, user_profile, opts): + if user_profile: + container = DefaultUserContainer + else: + container = radius_util.profiles_container + + uid = self.__safe_filter(uid) + filter = radius_util.radius_profile_filter(uid) + basedn = radius_util.radius_profiles_basedn(container, self.basedn) + + try: + entry = self.__get_sub_entry(basedn, filter, ['dn','uid'], opts) + return True + except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): + return False + + def add_radius_profile (self, uid, user_profile=True, opts=None): + if self.__radius_profile_exists(profile['uid'], user_profile, opts): + raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) + + if user_profile: + container = DefaultUserContainer + else: + container = radius_util.profiles_container + + dn = radius_util.radius_profile_dn(uid, container, self.basedn) + entry = ipaserver.ipaldap.Entry(dn) + + # some required objectclasses + entry.setValues('objectClass', 'top', 'radiusClientProfile') + + # fill in our new entry with everything sent by the profile + for attr in profile: + entry.setValues(attr, profile[attr]) + + conn = self.getConnection(opts) + try: + res = conn.addEntry(entry) + finally: + self.releaseConnection(conn) + return res + + def update_radius_profile(self, oldentry, newentry, opts=None): + return self.update_entry(oldentry, newentry, opts) + + def delete_radius_profile(self, uid, user_profile, opts=None): + profile = self.get_radius_profile_by_uid(uid, user_profile, ['dn', 'cn'], opts) + if profile is None: + raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) + + conn = self.getConnection(opts) + try: + res = conn.deleteEntry(profile['dn']) + finally: + self.releaseConnection(conn) + return res + + def find_radius_profiles(self, uids, user_profile=True, sattrs=None, searchlimit=0, timelimit=-1, opts=None): + def gen_filter(objectclass, attr, values): + '''Given ('myclass', 'myattr', [v1, v2]) returns + (&(objectclass=myclass)(|(myattr=v1)(myattr=v2))) + ''' + # Don't use __safe_filter, prevents wildcarding + #attrs = ''.join(['(%s=%s)' % (attr, self.__safe_filter(val)) for val in values]) + attrs = ''.join(['(%s=%s)' % (attr, val) for val in values]) + filter = "(&(objectclass=%s)(|%s))" % (objectclass, attrs) + return filter + + if user_profile: + container = DefaultUserContainer + else: + container = radius_util.profiles_container + + uid = self.__safe_filter(uid) + filter = gen_filter('radiusClientProfile' 'uid', uids) + basedn="%s,%s" % (container, self.basedn) + conn = self.getConnection(opts) + try: + try: + results = conn.getListAsync(basedn, self.scope, filter, sattrs, 0, None, None, timelimit, searchlimit) + except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): + results = [0] + finally: + self.releaseConnection(conn) + + counter = results[0] + results = results[1:] + radius_profiles = [counter] + for radius_profile in results: + radius_profiles.append(self.convert_entry(radius_profile)) + + return radius_profiles + def get_add_schema (self): """Get the list of fields to be used when adding users in the GUI.""" diff --git a/ipa-server/xmlrpc-server/ipaxmlrpc.py b/ipa-server/xmlrpc-server/ipaxmlrpc.py index d5bdb6b2..ef48f4aa 100644 --- a/ipa-server/xmlrpc-server/ipaxmlrpc.py +++ b/ipa-server/xmlrpc-server/ipaxmlrpc.py @@ -356,6 +356,11 @@ def handler(req, profiling=False): h.register_function(f.update_radius_client) h.register_function(f.delete_radius_client) h.register_function(f.find_radius_clients) + h.register_function(f.get_radius_profile_by_uid) + h.register_function(f.add_radius_profile) + h.register_function(f.update_radius_profile) + h.register_function(f.delete_radius_profile) + h.register_function(f.find_radius_profiles) h.handle_request(req) finally: pass |