def urlfetch(uri, trace_level=0): """ Fetches a parsed schema entry by uri. If uri is a LDAP URL the LDAP server is queried directly. Otherwise uri is assumed to point to a LDIF file which is loaded with urllib. """ uri = uri.strip() if uri.startswith('ldap:') or uri.startswith('ldaps:') or uri.startswith( 'ldapi:'): import ldapurl ldap_url = ldapurl.LDAPUrl(uri) # This is an internal function; don't enable bytes_mode. l = ldap.initialize(ldap_url.initializeUrl(), trace_level, bytes_mode=False) l.protocol_version = ldap.VERSION3 l.simple_bind_s(ldap_url.who or '', ldap_url.cred or '') subschemasubentry_dn = l.search_subschemasubentry_s(ldap_url.dn) if subschemasubentry_dn is None: s_temp = None else: if ldap_url.attrs is None: schema_attrs = SCHEMA_ATTRS else: schema_attrs = ldap_url.attrs s_temp = l.read_subschemasubentry_s(subschemasubentry_dn, attrs=schema_attrs) l.unbind_s() del l else: import ldif from ldap.compat import urlopen ldif_file = urlopen(uri) ldif_parser = ldif.LDIFRecordList(ldif_file, max_entries=1) ldif_parser.parse() subschemasubentry_dn, s_temp = ldif_parser.all_records[0] # Work-around for mixed-cased attribute names subschemasubentry_entry = ldap.cidict.cidict() s_temp = s_temp or {} for at, av in s_temp.items(): if at in SCHEMA_CLASS_MAPPING: try: subschemasubentry_entry[at].extend(av) except KeyError: subschemasubentry_entry[at] = av # Finally parse the schema if subschemasubentry_dn != None: parsed_sub_schema = ldap.schema.SubSchema(subschemasubentry_entry) else: parsed_sub_schema = None return subschemasubentry_dn, parsed_sub_schema
def _next_key_and_value(self): """ Parse a single attribute type and value pair from one or more lines of LDIF data Returns attr_type (text) and attr_value (bytes) """ # Reading new attribute line unfolded_line = self._unfold_lines() # Ignore comments which can also be folded while unfolded_line and unfolded_line[0] == '#': unfolded_line = self._unfold_lines() if not unfolded_line: return None, None if unfolded_line == '-': return '-', None try: colon_pos = unfolded_line.index(':') except ValueError as e: raise ValueError('no value-spec in %s' % (repr(unfolded_line))) attr_type = unfolded_line[0:colon_pos] # if needed attribute value is BASE64 decoded value_spec = unfolded_line[colon_pos:colon_pos + 2] if value_spec == ': ': attr_value = unfolded_line[colon_pos + 2:].lstrip() # All values should be valid ascii; we support UTF-8 as a # non-official, backwards compatibility layer. attr_value = attr_value.encode('utf-8') elif value_spec == '::': # attribute value needs base64-decoding # base64 makes sens only for ascii attr_value = unfolded_line[colon_pos + 2:] attr_value = attr_value.encode('ascii') attr_value = self._b64decode(attr_value) elif value_spec == ':<': # fetch attribute value from URL url = unfolded_line[colon_pos + 2:].strip() attr_value = None if self._process_url_schemes: u = urlparse(url) if u[0] in self._process_url_schemes: attr_value = urlopen(url).read() else: # All values should be valid ascii; we support UTF-8 as a # non-official, backwards compatibility layer. attr_value = unfolded_line[colon_pos + 1:].encode('utf-8') return attr_type, attr_value