Use GSSAPI auth for the ipa-replica-manage list and del commands.

This creates a new role, replicaadmin, so a non-DM user can do
limited management of replication agreements.

Note that with cn=config if an unauthorized user performs a search
an error is not returned, no entries are returned. This makes it
difficult to determine if there are simply no replication agreements or
we aren't allowed to see them. Once the ipaldap.py module gets
replaced by ldap2 we can use Get Effective Rights to easily tell the
difference.
This commit is contained in:
Rob Crittenden 2010-02-19 13:29:14 -05:00
parent 664ae51eb6
commit c19911845d
4 changed files with 76 additions and 5 deletions

View File

@ -27,6 +27,7 @@ from ipaserver.install import replication, dsinstance, installutils
from ipaserver import ipaldap
from ipapython import version
from ipalib import util
from ipalib import errors
def parse_options():
from optparse import OptionParser
@ -102,12 +103,15 @@ def del_master(replman, hostname, force=False):
try:
t = replman.get_agreement_type(hostname)
except ldap.NO_SUCH_OBJECT:
print "No replication agreement found for %s" % hostname
print "No replication agreement found for '%s'" % hostname
return
except errors.NotFound:
print "No replication agreement found for '%s'" % hostname
return
if t == replication.IPA_REPLICA:
dirman_passwd = getpass.getpass("Directory Manager password (%s): " % hostname)
try:
other_replman = replication.ReplicationManager(hostname, dirman_passwd)
other_replman = replication.ReplicationManager(hostname, dirman_passwd=None)
other_replman.suffix = get_suffix()
other_replman.delete_agreement(replman.conn.host)
except Exception, e:
@ -179,10 +183,13 @@ def synch_master(replman, hostname):
def main():
options, args = parse_options()
dirman_passwd = None
if options.dirman_passwd:
dirman_passwd = options.dirman_passwd
else:
dirman_passwd = getpass.getpass("Directory Manager password: ")
if args[0] in ["add", "init"]:
dirman_passwd = getpass.getpass("Directory Manager password: ")
if options.host:
host = options.host
@ -227,5 +234,12 @@ except SystemExit, e:
except ldap.INVALID_CREDENTIALS:
print "Invalid password"
sys.exit(1)
except ldap.INSUFFICIENT_ACCESS:
print "Insufficient access"
sys.exit(1)
except ldap.LOCAL_ERROR, e:
print e.args[0]['info']
sys.exit(1)
except Exception, e:
print "unexpected error: %s" % str(e)
sys.exit(1)

View File

@ -72,6 +72,13 @@ add:objectClass: nestedgroup
add:cn: certadmin
add:description: Certificate Administrators
dn: cn=replicaadmin,cn=rolegroups,cn=accounts,$SUFFIX
add:objectClass: top
add:objectClass: nestedgroup
add:cn: replicaadmin
add:description: Replication Administrators
add:member:'uid=admin,cn=users,cn=accounts,$SUFFIX'
# Add the taskgroups referenced by the ACIs for user administration
dn: cn=taskgroups,cn=accounts,$SUFFIX
@ -648,3 +655,33 @@ add: aci: '(targetattr = "objectClass")(target =
$SUFFIX" )(version 3.0 ; acl "Certificate Remove Hold"
; allow (write) groupdn = "ldap:///cn=certificate_remove_hold,
cn=taskgroups,cn=accounts,$SUFFIX";)'
# Taskgroup for managing replicas
dn: cn=managereplica,cn=taskgroups,cn=accounts,$SUFFIX
add:objectClass: top
add:objectClass: nestedgroup
add:cn: managereplica
add:description: Manage Replication Agreements
add:member:'cn=replicaadmin,cn=rolegroups,cn=accounts,$SUFFIX'
# Taskgroup for deleting replicas
dn: cn=deletereplica,cn=taskgroups,cn=accounts,$SUFFIX
add:objectClass: top
add:objectClass: nestedgroup
add:cn: deletereplica
add:description: Delete Replication Agreements
add:member:'cn=replicaadmin,cn=rolegroups,cn=accounts,$SUFFIX'
# Add acis allowing admins to read/write/delete replicas
dn: cn="$SUFFIX",cn=mapping tree,cn=config
add: aci: '(targetattr=*)(targetfilter="(|(objectclass=nsds5Replica)
(objectclass=nsds5replicationagreement)(objectclass=
nsDSWindowsReplicationAgreement))")(version 3.0; acl "Manage
replication agreements"; allow (read, write, search) groupdn =
"ldap:///cn=managereplica,cn=taskgroups,cn=accounts,$SUFFIX";)'
dn: cn="$SUFFIX",cn=mapping tree,cn=config
add: aci: '(targetattr=*)(targetfilter="(|(objectclass=
nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement
))")(version 3.0;acl "Delete replication agreements";allow (delete)
groupdn = "ldap:///cn=deletereplica,cn=taskgroups,cn=accounts,$SUFFIX";)'

View File

@ -148,6 +148,8 @@ class DsInstance(service.Service):
self.pkcs12_info = None
self.ds_user = None
self.dercert = None
self.uidstart = 1100
self.gidstart = 1100
if realm_name:
self.suffix = util.realm_to_suffix(self.realm_name)
self.__setup_sub_dict()

View File

@ -38,6 +38,8 @@ TIMEOUT = 120
IPA_REPLICA = 1
WINSYNC = 2
SASL_AUTH = ldap.sasl.sasl({}, 'GSSAPI')
class ReplicationManager:
"""Manage replication agreements between DS servers, and sync
agreements with Windows servers"""
@ -45,8 +47,13 @@ class ReplicationManager:
self.hostname = hostname
self.dirman_passwd = dirman_passwd
# If we are passed a password we'll use it as the DM password
# otherwise we'll do a GSSAPI bind.
self.conn = ipaldap.IPAdmin(hostname, port=PORT, cacert=CACERT)
self.conn.do_simple_bind(bindpw=dirman_passwd)
if dirman_passwd:
self.conn.do_simple_bind(bindpw=dirman_passwd)
else:
self.conn.sasl_interactive_bind_s('', SASL_AUTH)
self.repl_man_passwd = dirman_passwd
@ -98,6 +105,16 @@ class ReplicationManager:
return retval
def find_replication_dns(self, conn):
"""
The replication agreements are stored in
cn="$SUFFIX",cn=mapping tree,cn=config
FIXME: Rather than failing with a read error if a user tries
to read this it simply returns zero entries. We need to use
GER to determine if we are allowed to read this to return a proper
response. For now just return "No entries" even if the user may
not be allowed to see them.
"""
filt = "(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement))"
try:
ents = conn.search_s("cn=mapping tree,cn=config", ldap.SCOPE_SUBTREE, filt)
@ -465,6 +482,7 @@ class ReplicationManager:
# allow connections using two different CA certs
other_conn = ipaldap.IPAdmin(other_hostname, port=oth_port, cacert=oth_cacert)
try:
# For now we always require a password to set up new replica
other_conn.do_simple_bind(binddn=oth_binddn, bindpw=oth_bindpw)
except Exception, e:
if iswinsync: