diff options
author | rcritten@redhat.com <rcritten@redhat.com> | 2007-08-06 10:05:53 -0400 |
---|---|---|
committer | rcritten@redhat.com <rcritten@redhat.com> | 2007-08-06 10:05:53 -0400 |
commit | 993f76fe6035cf59cceb88f3611fc53680738007 (patch) | |
tree | 17bb5afed002709bd322f5fe7e99e473adc1d018 /ipa-server/xmlrpc-server | |
parent | 66ab69d0b23da46b21dbb4bf165011f318ec2da8 (diff) | |
download | freeipa-993f76fe6035cf59cceb88f3611fc53680738007.tar.gz freeipa-993f76fe6035cf59cceb88f3611fc53680738007.tar.xz freeipa-993f76fe6035cf59cceb88f3611fc53680738007.zip |
- Abstracted client class to work directly or over RPC
- Add mod_auth_kerb and cyrus-sasl-gssapi to Requires
- Remove references to admin server in ipa-server-setupssl
- Generate a client certificate for the XML-RPC server to connect to LDAP with
- Create a keytab for Apache
- Create an ldif with a test user
- Provide a certmap.conf for doing SSL client authentication
- Update tools to use kerberos
- Add User class
Diffstat (limited to 'ipa-server/xmlrpc-server')
-rw-r--r-- | ipa-server/xmlrpc-server/funcs.py | 339 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/ipa.conf | 18 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/ipaxmlrpc.py | 17 |
3 files changed, 217 insertions, 157 deletions
diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py index be95d4fab..9545ad892 100644 --- a/ipa-server/xmlrpc-server/funcs.py +++ b/ipa-server/xmlrpc-server/funcs.py @@ -24,152 +24,205 @@ import ldap import ipaserver.dsinstance import ipaserver.ipaldap import ipaserver.util -import pdb import string from types import * import xmlrpclib import ipa.config -# FIXME, this needs to be auto-discovered -host = 'localhost' -port = 389 -binddn = "cn=directory manager" -bindpw = "freeipa" - -ipa.config.init_config() -basedn = ipaserver.util.realm_to_suffix(ipa.config.config.get_realm()) -import sys -sys.stderr.write(basedn) -scope = ldap.SCOPE_SUBTREE - -def get_user (username): - """Get a specific user's entry. Return as a dict of values. - Multi-valued fields are represented as lists. - """ - ent="" - - # FIXME: Is this the filter we want or should it be more specific? - filter = "(uid=" + username + ")" - try: - m1 = ipaserver.ipaldap.IPAdmin(host,port,binddn,bindpw) - ent = m1.getEntry(basedn, scope, filter, None) - except ldap.LDAPError, e: - raise xmlrpclib.Fault(1, e) - except ipaserver.ipaldap.NoSuchEntryError: - raise xmlrpclib.Fault(2, "No such user") - - # Convert to LDIF - entry = str(ent) - - # Strip off any junk - entry = entry.strip() - - # Don't need to identify binary fields and this breaks the parser so - # remove double colons - entry = entry.replace('::', ':') - specs = [spec.split(':') for spec in entry.split('\n')] - - # Convert into a dict. We need to handle multi-valued attributes as well - # so we'll convert those into lists. - user={} - for (k,v) in specs: - k = k.lower() - if user.get(k) is not None: - if isinstance(user[k],list): - user[k].append(v.strip()) +class IPAServer: + + def __init__(self): + # FIXME, this needs to be auto-discovered + self.host = 'localhost' + self.port = 636 + self.bindcert = "/usr/share/ipa/cert.pem" + self.bindkey = "/usr/share/ipa/key.pem" + self.bindca = "/usr/share/ipa/cacert.asc" + + ipa.config.init_config() + self.basedn = ipaserver.util.realm_to_suffix(ipa.config.config.get_realm()) + self.scope = ldap.SCOPE_SUBTREE + self.princ = None + + def set_principal(self, princ): + self.princ = princ + + def get_dn_from_principal(self, princ): + """Given a kerberls principal get the LDAP uid""" + filter = "(krbPrincipalName=" + princ + ")" + try: + m1 = ipaserver.ipaldap.IPAdmin(self.host,self.port,self.bindca,self.bindcert,self.bindkey) + ent = m1.getEntry(self.basedn, self.scope, filter, None) + except ldap.LDAPError, e: + raise xmlrpclib.Fault(1, e) + except ipaserver.ipaldap.NoSuchEntryError: + raise xmlrpclib.Fault(2, "No such user") + + return "dn:" + ent.dn + + def convert_entry(self, ent): + + # Convert to LDIF + entry = str(ent) + + # Strip off any junk + entry = entry.strip() + + # Don't need to identify binary fields and this breaks the parser so + # remove double colons + entry = entry.replace('::', ':') + specs = [spec.split(':') for spec in entry.split('\n')] + + # Convert into a dict. We need to handle multi-valued attributes as well + # so we'll convert those into lists. + user={} + for (k,v) in specs: + k = k.lower() + if user.get(k) is not None: + if isinstance(user[k],list): + user[k].append(v.strip()) + else: + first = user[k] + user[k] = [] + user[k].append(first) + user[k].append(v.strip()) else: - first = user[k] - user[k] = [] - user[k].append(first) - user[k].append(v.strip()) - else: - user[k] = v.strip() - - return user -# return str(ent) # return as LDIF - -def add_user (user): - """Add a user in LDAP""" - dn="uid=%s,ou=users,ou=default,%s" % (user['uid'], basedn) - entry = ipaserver.ipaldap.Entry(dn) - - # some required objectclasses - entry.setValues('objectClass', 'top', 'posixAccount', 'shadowAccount', 'account', 'person', 'inetOrgPerson', 'organizationalPerson', 'krbPrincipalAux', 'krbTicketPolicyAux') - - # Fill in shadow fields - entry.setValue('shadowMin', '0') - entry.setValue('shadowMax', '99999') - entry.setValue('shadowWarning', '7') - entry.setValue('shadowExpire', '-1') - entry.setValue('shadowInactive', '-1') - entry.setValue('shadowFlag', '-1') - - # FIXME: calculate shadowLastChange - - # fill in our new entry with everything sent by the user - for u in user: - entry.setValues(u, user[u]) - - try: - m1 = ipaserver.ipaldap.IPAdmin(host,port,binddn,bindpw) - res = m1.addEntry(entry) - return res - except ldap.ALREADY_EXISTS: - raise xmlrpclib.Fault(3, "User already exists") - return None - except ldap.LDAPError, e: - raise xmlrpclib.Fault(1, str(e)) - return None - -def get_add_schema (): - """Get the list of fields to be used when adding users in the GUI.""" - - # FIXME: this needs to be pulled from LDAP - fields = [] - - field1 = { - "name": "uid" , - "label": "Login:", - "type": "text", - "validator": "text", - "required": "true" - } - fields.append(field1) - - field1 = { - "name": "userPassword" , - "label": "Password:", - "type": "password", - "validator": "String", - "required": "true" - } - fields.append(field1) - - field1 = { - "name": "givenName" , - "label": "First name:", - "type": "text", - "validator": "string", - "required": "true" - } - fields.append(field1) - - field1 = { - "name": "sn" , - "label": "Last name:", - "type": "text", - "validator": "string", - "required": "true" - } - fields.append(field1) - - field1 = { - "name": "mail" , - "label": "E-mail address:", - "type": "text", - "validator": "email", - "required": "true" - } - fields.append(field1) - - return fields + user[k] = v.strip() + + return user + + def get_user (self, username, opts=None): + """Get a specific user's entry. Return as a dict of values. + Multi-valued fields are represented as lists. + """ + ent="" + if opts: + self.set_principal(opts['remoteuser']) + if (isinstance(username, tuple)): + username = username[0] + + try: + dn = self.get_dn_from_principal(self.princ) + except ldap.LDAPError, e: + raise xmlrpclib.Fault(1, e) + except ipaserver.ipaldap.NoSuchEntryError: + raise xmlrpclib.Fault(2, "No such user") + + filter = "(uid=" + username + ")" + try: + m1 = ipaserver.ipaldap.IPAdmin(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn) + ent = m1.getEntry(self.basedn, self.scope, filter, None) + except ldap.LDAPError, e: + raise xmlrpclib.Fault(1, e) + except ipaserver.ipaldap.NoSuchEntryError: + raise xmlrpclib.Fault(2, "No such user") + + return self.convert_entry(ent) + + def add_user (self, user, opts=None): + """Add a user in LDAP""" + if (isinstance(user, tuple)): + user = user[0] + dn="uid=%s,ou=users,ou=default,%s" % (user['uid'], self.basedn) + entry = ipaserver.ipaldap.Entry(str(dn)) + + # some required objectclasses + entry.setValues('objectClass', 'top', 'posixAccount', 'shadowAccount', 'account', 'person', 'inetOrgPerson', 'organizationalPerson', 'krbPrincipalAux', 'krbTicketPolicyAux') + + # Fill in shadow fields + entry.setValue('shadowMin', '0') + entry.setValue('shadowMax', '99999') + entry.setValue('shadowWarning', '7') + entry.setValue('shadowExpire', '-1') + entry.setValue('shadowInactive', '-1') + entry.setValue('shadowFlag', '-1') + + # FIXME: calculate shadowLastChange + + # fill in our new entry with everything sent by the user + for u in user: + entry.setValues(str(u), str(user[u])) + + if opts: + self.set_principal(opts['remoteuser']) + + try: + dn = self.get_dn_from_principal(self.princ) + except ldap.LDAPError, e: + raise xmlrpclib.Fault(1, e) + except ipaserver.ipaldap.NoSuchEntryError: + raise xmlrpclib.Fault(2, "No such user") + + try: + m1 = ipaserver.ipaldap.IPAdmin(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn) + res = m1.addEntry(entry) + return res + except ldap.ALREADY_EXISTS: + raise xmlrpclib.Fault(3, "User already exists") + except ldap.LDAPError, e: + raise xmlrpclib.Fault(1, str(e)) + + def get_add_schema (self): + """Get the list of fields to be used when adding users in the GUI.""" + + # FIXME: this needs to be pulled from LDAP + fields = [] + + field1 = { + "name": "uid" , + "label": "Login:", + "type": "text", + "validator": "text", + "required": "true" + } + fields.append(field1) + + field1 = { + "name": "givenName" , + "label": "First name:", + "type": "text", + "validator": "string", + "required": "true" + } + fields.append(field1) + + field1 = { + "name": "sn" , + "label": "Last name:", + "type": "text", + "validator": "string", + "required": "true" + } + fields.append(field1) + + field1 = { + "name": "mail" , + "label": "E-mail address:", + "type": "text", + "validator": "email", + "required": "true" + } + fields.append(field1) + + return fields + + def get_all_users (self): + """Return a list containing a User object for each + existing user. + """ + + # FIXME: Is this the filter we want or should it be more specific? + filter = "(objectclass=posixAccount)" + try: + m1 = ipaserver.ipaldap.IPAdmin(self.host,self.port,self.bindca,self.bindcert,self.bindkey) + all_users = m1.getList(self.basedn, self.scope, filter, None) + except ldap.LDAPError, e: + raise xmlrpclib.Fault(1, e) + except ipaserver.ipaldap.NoSuchEntryError: + raise xmlrpclib.Fault(2, "No such user") + + users = [] + for u in all_users: + users.append(self.convert_entry(u)) + + return users diff --git a/ipa-server/xmlrpc-server/ipa.conf b/ipa-server/xmlrpc-server/ipa.conf index 1880268cf..dbe6b99fd 100644 --- a/ipa-server/xmlrpc-server/ipa.conf +++ b/ipa-server/xmlrpc-server/ipa.conf @@ -3,15 +3,15 @@ Alias /ipa "/usr/share/ipa/ipaserver/XMLRPC" <Directory "/usr/share/ipa/ipaserver"> -# AuthType Kerberos -# AuthName "Kerberos Login" -# KrbMethodNegotiate on -# KrbMethodK5Passwd off -# KrbServiceName HTTP -# KrbAuthRealms GREYOAK.COM -# Krb5KeyTab /etc/httpd/conf/ipa.keytab -# KrbSaveCredentials on -# Require valid-user + AuthType Kerberos + AuthName "Kerberos Login" + KrbMethodNegotiate on + KrbMethodK5Passwd off + KrbServiceName HTTP + KrbAuthRealms GREYOAK.COM + Krb5KeyTab /etc/httpd/conf/ipa.keytab + KrbSaveCredentials on + Require valid-user ErrorDocument 401 /errors/unauthorized.html SetHandler mod_python diff --git a/ipa-server/xmlrpc-server/ipaxmlrpc.py b/ipa-server/xmlrpc-server/ipaxmlrpc.py index ad5e30683..7bad9ab5e 100644 --- a/ipa-server/xmlrpc-server/ipaxmlrpc.py +++ b/ipa-server/xmlrpc-server/ipaxmlrpc.py @@ -123,11 +123,16 @@ class ModXMLRPCRequestHandler(object): def register_instance(self,instance): self.register_module(instance) - def _marshaled_dispatch(self, data): + def _marshaled_dispatch(self, data, remoteuser): """Dispatches an XML-RPC method from marshalled (XML) data.""" params, method = loads(data) + opts={} + opts['remoteuser'] = remoteuser + + params = ipaserver.encode_args(params, opts) + # special case # if method == "get_user": # Marshaller._Marshaller__dump = xmlrpclib_dump @@ -239,7 +244,7 @@ class ModXMLRPCRequestHandler(object): req.allow_methods(['POST'],1) raise apache.SERVER_RETURN, apache.HTTP_METHOD_NOT_ALLOWED - response = self._marshaled_dispatch(req.read()) + response = self._marshaled_dispatch(req.read(), req.user) req.content_type = "text/xml" req.set_content_length(len(response)) @@ -267,10 +272,12 @@ def handler(req, profiling=False): else: opts = req.get_options() try: + f = funcs.IPAServer() h = ModXMLRPCRequestHandler() - h.register_function(funcs.get_user) - h.register_function(funcs.add_user) - h.register_function(funcs.get_add_schema) + h.register_function(f.get_user) + h.register_function(f.add_user) + h.register_function(f.get_add_schema) + h.register_function(f.get_all_users) h.handle_request(req) finally: pass |