mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-28 01:41:14 -06:00
255 lines
9.1 KiB
Python
255 lines
9.1 KiB
Python
|
# Authors:
|
||
|
# Alexander Bokovoy <abokovoy@redhat.com>
|
||
|
#
|
||
|
# Copyright (C) 2011 Red Hat
|
||
|
# see file 'COPYING' for use and warranty information
|
||
|
#
|
||
|
# This program is free software; you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation, either version 3 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
from ipalib.plugins.baseldap import *
|
||
|
from ipalib import api, Str, Password, DefaultFrom, _, ngettext, Object
|
||
|
from ipalib.parameters import Enum
|
||
|
from ipalib import Command
|
||
|
from ipalib import errors
|
||
|
from ipapython import ipautil
|
||
|
from ipalib import util
|
||
|
if api.env.in_server and api.env.context in ['lite', 'server']:
|
||
|
try:
|
||
|
import ipaserver.dcerpc
|
||
|
_bindings_installed = True
|
||
|
except Exception, e:
|
||
|
_bindings_installed = False
|
||
|
|
||
|
__doc__ = _("""
|
||
|
Manage trust relationship between realms
|
||
|
""")
|
||
|
|
||
|
trust_output_params = (
|
||
|
Str('ipantflatname',
|
||
|
label=_('Domain NetBIOS name')),
|
||
|
Str('ipantsecurityidentifier',
|
||
|
label=_('Domain Security Identifier')),
|
||
|
Str('trustdirection',
|
||
|
label=_('Trust direction')),
|
||
|
Str('trusttype',
|
||
|
label=_('Trust type')),
|
||
|
Str('truststatus',
|
||
|
label=_('Trust status')),
|
||
|
)
|
||
|
|
||
|
_trust_type_dict = {1 : _('Non-Active Directory domain'),
|
||
|
2 : _('Active Directory domain'),
|
||
|
3 : _('RFC4120-compliant Kerberos realm')}
|
||
|
_trust_direction_dict = {1 : _('Trusting forest'),
|
||
|
2 : _('Trusted forest'),
|
||
|
3 : _('Two-way trust')}
|
||
|
_trust_status = {1 : _('Established and verified'),
|
||
|
2 : _('Waiting for confirmation by remote side')}
|
||
|
_trust_type_dict_unknown = _('Unknown')
|
||
|
|
||
|
def trust_type_string(level):
|
||
|
"""
|
||
|
Returns a string representing a type of the trust. The original field is an enum:
|
||
|
LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001,
|
||
|
LSA_TRUST_TYPE_UPLEVEL = 0x00000002,
|
||
|
LSA_TRUST_TYPE_MIT = 0x00000003
|
||
|
"""
|
||
|
string = _trust_type_dict.get(int(level), _trust_type_dict_unknown)
|
||
|
return unicode(string)
|
||
|
|
||
|
def trust_direction_string(level):
|
||
|
"""
|
||
|
Returns a string representing a direction of the trust. The original field is a bitmask taking two bits in use
|
||
|
LSA_TRUST_DIRECTION_INBOUND = 0x00000001,
|
||
|
LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002
|
||
|
"""
|
||
|
string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown)
|
||
|
return unicode(string)
|
||
|
|
||
|
def trust_status_string(level):
|
||
|
string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown)
|
||
|
return unicode(string)
|
||
|
|
||
|
class trust(LDAPObject):
|
||
|
"""
|
||
|
Trust object.
|
||
|
"""
|
||
|
trust_types = ('ad', 'ipa')
|
||
|
container_dn = api.env.container_trusts
|
||
|
object_name = _('trust')
|
||
|
object_name_plural = _('trusts')
|
||
|
object_class = ['ipaNTTrustedDomain']
|
||
|
default_attributes = ['cn', 'ipantflatname', 'ipantsecurityidentifier',
|
||
|
'ipanttrusttype', 'ipanttrustattributes', 'ipanttrustdirection', 'ipanttrustpartner',
|
||
|
'ipantauthtrustoutgoing', 'ipanttrustauthincoming', 'ipanttrustforesttrustinfo',
|
||
|
'ipanttrustposixoffset', 'ipantsupportedencryptiontypes' ]
|
||
|
|
||
|
label = _('Trusts')
|
||
|
label_singular = _('Trust')
|
||
|
|
||
|
takes_params = (
|
||
|
Str('cn',
|
||
|
cli_name='realm',
|
||
|
label=_('Realm name'),
|
||
|
primary_key=True,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
def make_trust_dn(env, trust_type, dn):
|
||
|
if trust_type in trust.trust_types:
|
||
|
container_dn = DN(('cn', trust_type), env.container_trusts, env.basedn)
|
||
|
return unicode(DN(DN(dn)[0], container_dn))
|
||
|
return dn
|
||
|
|
||
|
class trust_add_ad(LDAPCreate):
|
||
|
__doc__ = _('Add new trust to use against Active Directory domain.')
|
||
|
|
||
|
takes_options = (
|
||
|
Str('realm_admin?',
|
||
|
cli_name='admin',
|
||
|
label=_("Active Directory domain administrator"),
|
||
|
),
|
||
|
Password('realm_passwd?',
|
||
|
cli_name='password',
|
||
|
label=_("Active directory domain adminstrator's password"),
|
||
|
confirm=False,
|
||
|
),
|
||
|
Str('realm_server?',
|
||
|
cli_name='server',
|
||
|
label=_('Domain controller for the Active Directory domain (optional)'),
|
||
|
),
|
||
|
Password('trust_secret?',
|
||
|
cli_name='trust_secret',
|
||
|
label=_('Shared secret for the trust'),
|
||
|
confirm=False,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
|
||
|
msg_summary = _('Added Active Directory trust for realm "%(value)s"')
|
||
|
|
||
|
def execute(self, *keys, **options):
|
||
|
# Join domain using full credentials and with random trustdom
|
||
|
# secret (will be generated by the join method)
|
||
|
trustinstance = None
|
||
|
if not _bindings_installed:
|
||
|
raise errors.NotFound(name=_('AD Trust setup'),
|
||
|
reason=_('''Cannot perform join operation without Samba 4 support installed.
|
||
|
Make sure you have installed server-trust-ad sub-package of IPA'''))
|
||
|
|
||
|
if 'realm_server' not in options:
|
||
|
realm_server = None
|
||
|
else:
|
||
|
realm_server = options['realm_server']
|
||
|
|
||
|
trustinstance = ipaserver.dcerpc.TrustDomainJoins(self.api)
|
||
|
|
||
|
# 1. Full access to the remote domain. Use admin credentials and
|
||
|
# generate random trustdom password to do work on both sides
|
||
|
if 'realm_admin' in options:
|
||
|
realm_admin = options['realm_admin']
|
||
|
|
||
|
if 'realm_passwd' not in options:
|
||
|
raise errors.ValidationError(name=_('AD Trust setup'), reason=_('Realm administrator password should be specified'))
|
||
|
realm_passwd = options['realm_passwd']
|
||
|
|
||
|
result = trustinstance.join_ad_full_credentials(keys[-1], realm_server, realm_admin, realm_passwd)
|
||
|
|
||
|
if result is None:
|
||
|
raise errors.ValidationError(name=_('AD Trust setup'), reason=_('Unable to verify write permissions to the AD'))
|
||
|
|
||
|
return dict(result=dict(), value=trustinstance.remote_domain.info['dns_domain'])
|
||
|
|
||
|
# 2. We don't have access to the remote domain and trustdom password
|
||
|
# is provided. Do the work on our side and inform what to do on remote
|
||
|
# side.
|
||
|
if 'trust_secret' in options:
|
||
|
result = trustinstance.join_ad_ipa_half(keys[-1], realm_server, options['trust_secret'])
|
||
|
return dict(result=dict(), value=trustinstance.remote_domain.info['dns_domain'])
|
||
|
|
||
|
class trust_del(LDAPDelete):
|
||
|
__doc__ = _('Delete a trust.')
|
||
|
|
||
|
msg_summary = _('Deleted trust "%(value)s"')
|
||
|
|
||
|
def pre_callback(self, ldap, dn, *keys, **options):
|
||
|
try:
|
||
|
result = self.api.Command.trust_show(keys[-1])
|
||
|
except errors.NotFound, e:
|
||
|
self.obj.handle_not_found(*keys)
|
||
|
return result['result']['dn']
|
||
|
|
||
|
class trust_mod(LDAPUpdate):
|
||
|
__doc__ = _('Modify a trust.')
|
||
|
|
||
|
msg_summary = _('Modified trust "%(value)s"')
|
||
|
|
||
|
def pre_callback(self, ldap, dn, *keys, **options):
|
||
|
result = None
|
||
|
try:
|
||
|
result = self.api.Command.trust_show(keys[-1])
|
||
|
except errors.NotFound, e:
|
||
|
self.obj.handle_not_found(*keys)
|
||
|
|
||
|
# TODO: we found the trust object, now modify it
|
||
|
return result['result']['dn']
|
||
|
|
||
|
class trust_find(LDAPSearch):
|
||
|
__doc__ = _('Search for trusts.')
|
||
|
|
||
|
msg_summary = ngettext(
|
||
|
'%(count)d trust matched', '%(count)d trusts matched', 0
|
||
|
)
|
||
|
|
||
|
# Since all trusts types are stored within separate containers under 'cn=trusts',
|
||
|
# search needs to be done on a sub-tree scope
|
||
|
def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
|
||
|
return (filters, base_dn, ldap.SCOPE_SUBTREE)
|
||
|
|
||
|
class trust_show(LDAPRetrieve):
|
||
|
__doc__ = _('Display information about a trust.')
|
||
|
has_output_params = LDAPRetrieve.has_output_params + trust_output_params
|
||
|
|
||
|
def execute(self, *keys, **options):
|
||
|
error = None
|
||
|
result = None
|
||
|
for trust_type in trust.trust_types:
|
||
|
options['trust_show_type'] = trust_type
|
||
|
try:
|
||
|
result = super(trust_show, self).execute(*keys, **options)
|
||
|
except errors.NotFound, e:
|
||
|
result = None
|
||
|
error = e
|
||
|
if result:
|
||
|
result['result']['trusttype'] = [trust_type_string(result['result']['ipanttrusttype'][0])]
|
||
|
result['result']['trustdirection'] = [trust_direction_string(result['result']['ipanttrustdirection'][0])]
|
||
|
break
|
||
|
if error or not result:
|
||
|
self.obj.handle_not_found(*keys)
|
||
|
|
||
|
return result
|
||
|
|
||
|
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
|
||
|
if 'trust_show_type' in options:
|
||
|
return make_trust_dn(self.env, options['trust_show_type'], dn)
|
||
|
return dn
|
||
|
|
||
|
api.register(trust)
|
||
|
api.register(trust_add_ad)
|
||
|
api.register(trust_mod)
|
||
|
api.register(trust_del)
|
||
|
api.register(trust_find)
|
||
|
api.register(trust_show)
|
||
|
|