Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License.
'sub': ldap.SCOPE_SUBTREE} 'default': None, 'finding': ldap.DEREF_FINDING, 'never': ldap.DEREF_NEVER, 'searching': ldap.DEREF_SEARCHING} 'demand': ldap.OPT_X_TLS_DEMAND, 'allow': ldap.OPT_X_TLS_ALLOW}
if isinstance(val, str): return val elif isinstance(val, bool): return 'TRUE' if val else 'FALSE' else: return str(val)
try: return LDAP_VALUES[val] except KeyError: pass try: return int(val) except ValueError: pass return val
if attrs is None: return elif isinstance(attrs, list): for e in attrs: yield e else: yield attrs
opt) + ', '.join(LDAP_DEREF.keys()))
except KeyError: raise ValueError(_( 'Invalid LDAP TLS certs option: %(option). ' 'Choose one of: %(options)s') % { 'option': opt, 'options': ', '.join(LDAP_TLS_CERTS.keys())})
_('Invalid LDAP scope: %(scope)s. Choose one of: %(options)s') % { 'scope': scope, 'options': ', '.join(LDAP_SCOPES.keys())})
self.suffix = self.DEFAULT_SUFFIX or '%s,%s' % (self.DEFAULT_OU, self.suffix))
or self.DEFAULT_OBJECTCLASS)
self.options_name) or self.DEFAULT_EXTRA_ATTR_MAPPING)
self.DUMB_MEMBER_DN)
'allow_subtree_delete')
return exception.NotFound(target=object_id) else:
'Invalid additional attribute mapping: "%s". ' 'Format must be <ldap_attribute>:<keystone_attribute>') % item) 'Value "%(attr_map)s" must use one of %(keys)s.') % {'item': item, 'attr_map': attr_map, 'keys': ', '.join(self.attribute_mapping.keys())})
else: conn = LdapWrapper(self.LDAP_URL, self.page_size, alias_dereferencing=self.alias_dereferencing, use_tls=self.use_tls, tls_cacertfile=self.tls_cacertfile, tls_cacertdir=self.tls_cacertdir, tls_req_cert=self.tls_req_cert)
# not all LDAP servers require authentication, so we don't bind # if we don't have any user/pass
ldap.dn.escape_dn_chars(str(id)), self.tree_dn)
conn = self.get_connection() search_result = conn.search_s( self.tree_dn, self.LDAP_SCOPE, '(&(%(id_attr)s=%(id)s)(objectclass=%(objclass)s))' % {'id_attr': self.id_attr, 'id': ldap.filter.escape_filter_chars(str(id)), 'objclass': self.object_class}) if search_result: dn, attrs = search_result[0] return dn else: return self._id_to_dn_string(id)
def _dn_to_id(dn):
else: except IndexError: obj[k] = None
else: details=_('Duplicate name, %s.') % values['name'])
else: details=_('Duplicate ID, %s.') % values['id'])
in self.extra_attr_mapping.iteritems() if name == k]
'%(filter)s' '(objectClass=%(object_class)s))' % {'id_attr': self.id_attr, 'id': ldap.filter.escape_filter_chars(str(id)), 'filter': (filter or self.filter or ''), 'object_class': self.object_class}) self.extra_attr_mapping.keys()))) except ldap.NO_SUCH_OBJECT: return None
self.object_class) self.LDAP_SCOPE, query, self.attribute_mapping.values()) except ldap.NO_SUCH_OBJECT: return []
else:
ldap_filter.escape_filter_chars(name)))
for x in self._ldap_get_all(filter)]
if old_obj[k] is not None: modlist.append((ldap.MOD_DELETE, self.attribute_mapping.get(k, k), None)) op = ldap.MOD_ADD else:
except ldap.NO_SUCH_OBJECT: raise self._not_found(id)
conn = self.get_connection() tree_delete_control = ldap.controls.LDAPControl(CONTROL_TREEDELETE, 0, None) try: conn.delete_ext_s(self._id_to_dn(id), serverctrls=[tree_delete_control]) except ldap.NO_SUCH_OBJECT: raise self._not_found(id)
use_tls=False, tls_cacertfile=None, tls_cacertdir=None, tls_req_cert='demand'): LOG.debug(_("LDAP init: url=%s"), url) LOG.debug(_('LDAP init: use_tls=%(use_tls)s\n' 'tls_cacertfile=%(tls_cacertfile)s\n' 'tls_cacertdir=%(tls_cacertdir)s\n' 'tls_req_cert=%(tls_req_cert)s\n' 'tls_avail=%(tls_avail)s\n') % {'use_tls': use_tls, 'tls_cacertfile': tls_cacertfile, 'tls_cacertdir': tls_cacertdir, 'tls_req_cert': tls_req_cert, 'tls_avail': ldap.TLS_AVAIL })
#NOTE(topol) #for extra debugging uncomment the following line #ldap.set_option(ldap.OPT_DEBUG_LEVEL, 4095)
using_ldaps = url.lower().startswith("ldaps")
if use_tls and using_ldaps: raise AssertionError(_('Invalid TLS / LDAPS combination'))
if use_tls: if not ldap.TLS_AVAIL: raise ValueError(_('Invalid LDAP TLS_AVAIL option: %s. TLS ' 'not available') % ldap.TLS_AVAIL) if tls_cacertfile: #NOTE(topol) #python ldap TLS does not verify CACERTFILE or CACERTDIR #so we add some extra simple sanity check verification #Also, setting these values globally (i.e. on the ldap object) #works but these values are ignored when setting them on the #connection if not os.path.isfile(tls_cacertfile): raise IOError(_("tls_cacertfile %s not found " "or is not a file") % tls_cacertfile) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile) elif tls_cacertdir: #NOTE(topol) #python ldap TLS does not verify CACERTFILE or CACERTDIR #so we add some extra simple sanity check verification #Also, setting these values globally (i.e. on the ldap object) #works but these values are ignored when setting them on the #connection if not os.path.isdir(tls_cacertdir): raise IOError(_("tls_cacertdir %s not found " "or is not a directory") % tls_cacertdir) ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, tls_cacertdir) if tls_req_cert in LDAP_TLS_CERTS.values(): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_cert) else: LOG.debug(_("LDAP TLS: invalid TLS_REQUIRE_CERT Option=%s"), tls_req_cert)
self.conn = ldap.initialize(url) self.conn.protocol_version = ldap.VERSION3
if alias_dereferencing is not None: self.conn.set_option(ldap.OPT_DEREF, alias_dereferencing) self.page_size = page_size
if use_tls: self.conn.start_tls_s()
LOG.debug(_("LDAP bind: dn=%s"), user) return self.conn.simple_bind_s(user, password)
ldap_attrs = [(kind, [py2ldap(x) for x in safe_iter(values)]) for kind, values in attrs] if LOG.isEnabledFor(logging.DEBUG): sane_attrs = [(kind, values if kind != 'userPassword' else ['****']) for kind, values in ldap_attrs] LOG.debug(_('LDAP add: dn=%(dn)s, attrs=%(attrs)s') % { 'dn': dn, 'attrs': sane_attrs}) return self.conn.add_s(dn, ldap_attrs)
if LOG.isEnabledFor(logging.DEBUG): LOG.debug(_( 'LDAP search: dn=%(dn)s, scope=%(scope)s, query=%(query)s, ' 'attrs=%(attrlist)s') % { 'dn': dn, 'scope': scope, 'query': query, 'attrlist': attrlist}) if self.page_size: res = self.paged_search_s(dn, scope, query, attrlist) else: res = self.conn.search_s(dn, scope, query, attrlist)
o = [] for dn, attrs in res: o.append((dn, dict((kind, [ldap2py(x) for x in values]) for kind, values in attrs.iteritems()))) return o
res = [] lc = ldap.controls.SimplePagedResultsControl( controlType=ldap.LDAP_CONTROL_PAGE_OID, criticality=True, controlValue=(self.page_size, '')) msgid = self.conn.search_ext(dn, scope, query, attrlist, serverctrls=[lc]) # Endless loop request pages on ldap server until it has no data while True: # Request to the ldap server a page with 'page_size' entries rtype, rdata, rmsgid, serverctrls = self.conn.result3(msgid) # Receive the data res.extend(rdata) pctrls = [c for c in serverctrls if c.controlType == ldap.LDAP_CONTROL_PAGE_OID] if pctrls: # LDAP server supports pagination est, cookie = pctrls[0].controlValue if cookie: # There is more data still on the server # so we request another page lc.controlValue = (self.page_size, cookie) msgid = self.conn.search_ext(dn, scope, query, attrlist, serverctrls=[lc]) else: # Exit condition no more data on server break else: LOG.warning(_('LDAP Server does not support paging. ' 'Disable paging in keystone.conf to ' 'avoid this message.')) self._disable_paging() break return res
ldap_modlist = [ (op, kind, (None if values is None else [py2ldap(x) for x in safe_iter(values)])) for op, kind, values in modlist]
if LOG.isEnabledFor(logging.DEBUG): sane_modlist = [(op, kind, (values if kind != 'userPassword' else ['****'])) for op, kind, values in ldap_modlist] LOG.debug(_('LDAP modify: dn=%(dn)s, modlist=%(modlist)s') % { 'dn': dn, 'modlist': sane_modlist})
return self.conn.modify_s(dn, ldap_modlist)
LOG.debug(_("LDAP delete: dn=%s"), dn) return self.conn.delete_s(dn)
LOG.debug( _('LDAP delete_ext: dn=%(dn)s, serverctrls=%(serverctrls)s') % { 'dn': dn, 'serverctrls': serverctrls}) return self.conn.delete_ext_s(dn, serverctrls)
# Disable the pagination from now on self.page_size = 0
"""Emulates boolean 'enabled' attribute if turned on.
Creates groupOfNames holding all enabled objects of this class, all missing objects are considered disabled.
Options:
* $name_enabled_emulation - boolean, on/off * $name_enabled_emulation_dn - DN of that groupOfNames, default is cn=enabled_$name,$tree_dn
Where $name is self.options_name ('user' or 'tenant'), $tree_dn is self.tree_dn. """
(self.options_name, self.tree_dn))
ldap.SCOPE_BASE, query) else:
'member', [self._id_to_dn(object_id)])] ('member', [self._id_to_dn(object_id)])]
'member', [self._id_to_dn(object_id)])]
else:
# had to copy BaseLdap.get_all here to filter by DN for x in self._ldap_get_all(filter) if x[0] != self.enabled_emulation_dn] else:
else: else: object_id, values, old_obj)
|