class LdapMaillist(ldapdb.models.Model): """ Class for representing an LDAP Maillist entry. """ # LDAP meta-data base_dn = "ou=Mailinglists,dc=iapp-intern,dc=de" object_classes = ['groupOfNames', 'extensibleObject', ] # groupOfNames cn = CharField(db_column='cn', primary_key=True) description = CharField(db_column='description', blank=True) member = ListField(db_column='member') # extensibleObject mail = CharField(db_column='mail') owner = ListField(db_column='owner') rfc822MailMember = ListField(db_column='rfc822MailMember', blank=True) def __str__(self): return self.cn def __unicode__(self): return self.cn
class LdapGroup(ldapdb.models.Model): """ Class for representing an LDAP group entry. """ # LDAP meta-data base_dn = "ou=group,dc=iapp-intern,dc=de" object_classes = [ 'posixGroup', 'extensibleObject', ] # posixGroup cn = CharField(db_column='cn', primary_key=True) gidNumber = IntegerField(db_column='gidNumber', unique=True) description = CharField(db_column='description', blank=True) memberUid = ListField(db_column='memberUid') # extensibleObject owner = ListField(db_column='owner') def __str__(self): return self.cn def __unicode__(self): return self.cn
def test_list_field_contains(self): where = WhereNode() where.add((Constraint("memberUid", "memberUid", ListField()), 'contains', 'foouser'), AND) self.assertEquals(where_as_ldap(where), ("(memberUid=foouser)", [])) where = WhereNode() where.add((Constraint("memberUid", "memberUid", ListField()), 'contains', '(foouser)'), AND) self.assertEquals(where_as_ldap(where), ("(memberUid=\\28foouser\\29)", []))
class Group(BaseLdapModel): base_dn = force_text('ou=Groups,' + settings.LDAP_BASE_DN) object_classes = force_bytestrings(['posixGroup', 'sambaGroupMapping']) # posixGroup attributes name = CharField(db_column=force_text('cn'), max_length=200, primary_key=True, validators=list(name_validators)) gid = IntegerField(db_column=force_text('gidNumber'), unique=True) members = ListField(db_column=force_text('memberUid')) description = CharField(db_column=force_text('description'), max_length=500, blank=True, default='') group_type = IntegerField(db_column=force_text('sambaGroupType'), default=None) samba_sid = CharField(db_column=force_text('sambaSID'), unique=True, default='') def save(self, using=None): self.group_type = 2 self.set_next_free_value('gid', default=10000) # noinspection PyStringFormat self.samba_sid = '%s-%d' % (get_samba_sid(), self.gid) super(Group, self).save(using=using) group_of_names = list(GroupOfNames.objects.filter(name=self.name)[0:1]) if not group_of_names: group = GroupOfNames(name=self.name, members=['cn=admin,' + settings.LDAP_BASE_DN]) group.save() else: group = group_of_names[0] new_members = ['cn=admin,' + settings.LDAP_BASE_DN] + ['uid=%s,%s' % (x, User.base_dn) for x in self.members] if new_members != group.members: group.members = new_members group.save()
class Tag(ldapdb.models.Model): """ A Domesday tag. """ base_dn = "ou=tags,dc=mozillians,dc=org" object_classes = ['groupOfNames'] name = CharField(db_column='cn', max_length=32768, primary_key=True) members = ListField(db_column='member') description = CharField(db_column='description', max_length=1024) # Will eventually need a blesstag, and a field describing how to become # blessed. def members_as_people(self): # XXX want to say: # return [Person.objects.get(dn=dn) for dn in self.members] return [Person.objects.get(uid=dn.split(',')[0].split("=")[1]) for dn in self.members] def __str__(self): return self.name def __unicode__(self): return self.name
class LdapOA(ldapdb.models.Model): base_dn = "cn=OA,ou=Roles,dc=xiaoneng,dc=cn" object_classes = ['groupOfUniqueNames'] cn = CharField(db_column='cn', max_length=200, primary_key=True) uniqueMember = ListField(db_column='uniqueMember')
class GroupOfNames(BaseLdapModel): # a copy of Group, but based on different object classes. # required by nslcd! base_dn = 'ou=CoreGroups,' + settings.LDAP_BASE_DN object_classes = force_bytestrings(['groupOfNames']) name = CharField(db_column=force_text('cn'), max_length=200, primary_key=True, validators=list(name_validators)) members = ListField(db_column=force_text('member'))
class LDAPPosixUser(LDAPModel): """ Class for representing an LDAP user entry. """ objects = LDAPPosixUserManager() # LDAP meta-data base_dn = settings.LDAP_SYNC_USER_BASE_DN object_classes = ['top', 'posixAccount', 'inetOrgPerson'] # inetOrgPerson first_name = CharField(db_column='givenName', verbose_name="Prime name") last_name = CharField("Final name", db_column='sn') common_name = CharField(db_column='cn') email = ListField(db_column='mail') # posixAccount uid = IntegerField(db_column='uidNumber', default=1000) group = IntegerField(db_column='gidNumber') home_directory = CharField(db_column='homeDirectory') login_shell = CharField(db_column='loginShell', default='/bin/bash') nadine_id = CharField(db_column='uid', primary_key=True) password = CharField(db_column='userPassword') if hasattr(settings, 'LDAP_SYNC_USER_HOME_DIR_TEMPLATE'): HOME_DIR_TEMPLATE = settings.LDAP_SYNC_USER_HOME_DIR_TEMPLATE else: HOME_DIR_TEMPLATE = "/home/{}" def ensure_gid(self): """ If no group is set then perform a get_or_create() for default members group. """ if self.group is None: members_group, _ = LDAPPosixGroup.objects.get_or_create( name=settings.LDAP_SYNC_MEMBERS_GROUP_CN) self.group = members_group.gid def ensure_home_directory(self): """ If no home_directory is set then LDAP complains, we can auto-populate. """ if not self.home_directory: self.home_directory = self.HOME_DIR_TEMPLATE.format(self.uid) def save(self, *args, **kwargs): self.ensure_gid() self.ensure_home_directory() return super(LDAPPosixUser, self).save(*args, **kwargs) def __str__(self): return "{}:{}".format(self.nadine_id, self.common_name) def __str__(self): return self.full_name
class Tag(ldapdb.models.Model): """ A Domesday tag. """ base_dn = "ou=tags,dc=mozillians,dc=org" object_classes = ['groupOfNames'] name = CharField(db_column='cn', max_length=32768, primary_key=True) members = ListField(db_column='member') def __str__(self): return self.name def __unicode__(self): return self.name
class LdapGroup(ldapdb.models.Model): """ Class for representing an LDAP group entry. """ # LDAP meta-data base_dn = "ou=groups,dc=nodomain" object_classes = ['posixGroup'] # posixGroup attributes gid = IntegerField(db_column='gidNumber', unique=True) name = CharField(db_column='cn', max_length=200, primary_key=True) usernames = ListField(db_column='memberUid') def __str__(self): return self.name def __unicode__(self): return self.name
class LdapGroup(ldapdb.models.Model): """ Represents an LDAP posixGroup entry. """ connection_name = 'ldap' # LDAP meta-data base_dn = settings.LDAP_GROUP_DN object_classes = ['posixGroup'] # posixGroup attributes gid = IntegerField(db_column='gidNumber', unique=True) name = CharField(db_column='cn', max_length=200, primary_key=True) members = ListField(db_column='memberUid') def __str__(self): return self.name class Meta: managed = False
class LDAPPosixGroup(LDAPModel): """ Class for representing an LDAP group entry. """ objects = LDAPPosixGroupManager() # LDAP meta-data base_dn = settings.LDAP_SYNC_GROUP_BASE_DN object_classes = ['posixGroup'] # posixGroup attributes gid = IntegerField(db_column='gidNumber', default=500) name = CharField(db_column='cn', max_length=200, primary_key=True) usernames = ListField(db_column='memberUid') def __str__(self): return self.name def __str__(self): return self.name
class LdapGroup(ldapdb.models.Model): """ Represents LDAP group stored in LDAP directory, configured in settings.py """ # LDAP meta-data base_dn = "ou=Groups,dc=futurice,dc=com" # attributes gid = IntegerField(db_column='gidNumber', unique=True) name = CharField(db_column='cn', max_length=200, primary_key=True) members = ListField(db_column='uniqueMember') def __unicode__(self): return self.name @property def members_usernames(self): usernames = [] for member in self.members: # The members are given in ldap entries - we need to parse the user id from them matched = re.match(r'uid=(?P<uid>\w+?),.*', member) usernames.append(matched.group('uid')) return usernames
class GvUserPortal(ldapdb.models.Model): class Meta: managed = False base_dn = "dc=at" object_classes = ['gvUserPortal'] # RDN == Primary Key: cn is list field _only_ using a single value by convention cn = CharField(db_column='cn', max_length=250, primary_key=True) description = CharField(db_column='description', max_length=1024) gvAdminContactMail = ArrayField(CharField(db_column='gvAdminContactMail ', max_length=256),) gvAdminContactName = ArrayField(CharField(db_column='gvAdminContactName', max_length=256),) gvAdminContactTel = ArrayField(CharField(db_column='gvAdminContactTel', max_length=32),) gvDefaultParticipant = CharField(db_column='gvDefaultParticipant', max_length=32) gvMaxSecClass = IntegerField(db_column='gvMaxSecClass') gvParticipants = ListField(db_column='gvParticipants', ) gvPortalHotlineMail = ArrayField(CharField(db_column='gvPortalHotlineMail', max_length=250),) gvSupportedPvpProfile = ArrayField(CharField(db_column='gvSupportedPvpProfile', max_length=1024),) gvScope = CharField(db_column='gvScope', max_length=250) gvSource = CharField(db_column='gvSource', max_length=250) gvStatus = CharField(db_column='gvStatus', max_length=250) def __str__(self): return self.cn def __repl__(self): return self.dn def has_add_permission(self, request): return False # Allow viewing objects but not actually changing them. def has_change_permission(self, request, obj=None): return (request.method in ['GET', 'HEAD'] and super().has_change_permission(request, obj)) def has_delete_permission(self, request, obj=None): return False
class LdapUser(ldapdb.models.Model): """ Class for representing an LDAP user entry. """ # meta-data try: user_search = get_login_model() base_dn = user_search.user_ldapsearch except: pass object_classes = ['inetOrgPerson'] # 基类已经定义dn # dn = CharField(max_length=200, primary_key=True) username = CharField(db_column='cn', primary_key=True) # 定义多处主键时会影响到rdn的生成,最后完整dn生成规则是几个primarykey+base_dn组成。 user_sn = CharField(db_column='sn') email = CharField(db_column='mail', blank=True) phone = CharField(db_column='telephoneNumber', blank=True) password = CharField(db_column='userPassword') sshpublickey = CharField(db_column='sshpublickey', blank=True) memberof = ListField(db_column="memberOf", blank=True) def __str__(self): return self.username def __unicode__(self): return self.username def _save_table(self, raw=False, cls=None, force_insert=None, force_update=None, using=None, update_fields=None): """ Saves the current instance. """ # Connection aliasing connection = connections[using] create = bool(force_insert or not self.dn) # Prepare fields if update_fields: target_fields = [ self._meta.get_field(name) for name in update_fields ] else: target_fields = [ field for field in cls._meta.get_fields(include_hidden=True) if field.concrete and not field.primary_key ] def get_field_value(field, instance): python_value = getattr(instance, field.attname) return field.get_db_prep_save(python_value, connection=connection) if create: old = None else: old = cls.objects.using(using).get(pk=self.saved_pk) changes = { field.db_column: ( None if old is None else get_field_value(field, old), get_field_value(field, self), ) for field in target_fields } # Actual saving old_dn = self.dn new_dn = self.build_dn() updated = False # Insertion if create: # FIXME(rbarrois): This should be handled through a hidden field. hidden_values = [('objectClass', [ obj_class.encode('utf-8') for obj_class in self.object_classes ])] new_values = hidden_values + [ (colname, change[1]) for colname, change in sorted(changes.items()) if change[1] is not None ] new_dn = self.build_dn() logger.debug("Creating new LDAP entry %s", new_dn) connection.add_s(new_dn, new_values) # Update else: modlist = [] for colname, change in sorted(changes.items()): old_value, new_value = change if old_value == new_value: continue modlist.append(( ldap.MOD_DELETE if new_value is None else ldap.MOD_REPLACE, colname, new_value, )) # if new_dn != old_dn: # logger.debug("renaming ldap entry %s to %s", old_dn, new_dn) # connection.rename_s(old_dn, self.build_rdn()) # logger.debug("Modifying existing LDAP entry %s", new_dn) # connection.modify_s(new_dn, modlist) # updated = True # FIXME 重写了这个因为 build_dn 有坑 logger.debug("Modifying existing LDAP entry %s", old_dn) connection.modify_s(old_dn, modlist) updated = True self.dn = new_dn # Finishing self.saved_pk = self.pk return updated
class LDAPUser(ldapdb.models.Model): """ Class representing an LDAP user entry """ # LDAP metadata base_dn = settings.AUTH_LDAP_USER_BASE_DN object_classes = settings.AUTH_LDAP_USER_OBJECTCLASS # top object_class = ListField(db_column='objectClass') # person last_name = CharField(db_column='sn') full_name = CharField(db_column='cn') description = CharField(db_column='description') phone = CharField(db_column='telephoneNumber', blank=True) password = ListField(db_column='userPassword') # inetOrgPerson first_name = CharField(db_column='givenName') email = ListField(db_column='mail') username = CharField(db_column='uid', primary_key=True) # posixAccount uid = IntegerField(db_column='uidNumber', unique=True) gid = IntegerField(db_column='gidNumber') gecos = CharField(db_column='gecos') home_directory = CharField(db_column='homeDirectory') login_shell = CharField(db_column='loginShell', default='/bin/bash') # ldapPublicKey ssh_key = ListField(db_column='sshPublicKey') # gentooGroup ACL = ListField(db_column='gentooACL') birthday = DateField(db_column='birthday') developer_bug = ListField(db_column='gentooDevBug') gentoo_join_date = ListField(db_column='gentooJoin') gentoo_retire_date = ListField(db_column='gentooRetire') gpg_fingerprint = ListField(db_column='gpgfingerprint') gpg_key = ListField(db_column='gpgKey') gravatar = CharField(db_column='gravatar') im = ListField(db_column='gentooIM') latitude = FloatField(db_column='lat') location = CharField(db_column='gentooLocation') longitude = FloatField(db_column='lon') mentor = ListField(db_column='gentooMentor') otp_recovery_keys = ListField(db_column='gentooOTPRecoveryKey') otp_secret = CharField(db_column='gentooOTPSecret') planet_feed = CharField(db_column='gentooPlanetFeed') universe_feed = CharField(db_column='gentooUniverseFeed') website = ListField(db_column='website') # gentooDevGroup roles = CharField(db_column='gentooRoles') alias = ListField(db_column='gentooAlias') spf = ListField(db_column='gentooSPF') # additional ACL fields based on gentooACL is_user = ACLField(db_column='gentooACL') is_developer = ACLField(db_column='gentooACL') is_foundation = ACLField(db_column='gentooACL') is_staff = ACLField(db_column='gentooACL') is_docs = ACLField(db_column='gentooACL') is_council = ACLField(db_column='gentooACL') is_trustee = ACLField(db_column='gentooACL') is_overlays = ACLField(db_column='gentooACL') is_planet = ACLField(db_column='gentooACL') is_wiki = ACLField(db_column='gentooACL') is_forums = ACLField(db_column='gentooACL') is_security = ACLField(db_column='gentooACL') is_recruiter = ACLField(db_column='gentooACL') is_undertaker = ACLField(db_column='gentooACL') is_pr = ACLField(db_column='gentooACL') is_infra = ACLField(db_column='gentooACL') is_retired = ACLField(db_column='gentooACL') def __unicode__(self): return self.username
class Person(ldapdb.models.Model): """ A Domesday person. """ base_dn = "ou=people,dc=mozillians,dc=org" object_classes = ['inetOrgPerson', 'domesdayPerson'] uid = IntegerField(db_column='uid', max_length=256, primary_key=True) # Other fields to consider include: # timezone # lat/long (with UI to help users specify with an appropriate degree of # vagueness) cn = CharField(db_column='cn', max_length=32768) name = CharField(db_column='displayName', max_length=32768) familyName = CharField(db_column='sn', max_length=32768) nickname = CharField(db_column='domesdayNickName', max_length=32768) address = CharField(db_column='postalAddress', max_length=1024) locality = CharField(db_column='l', max_length=32768) country = CharField(db_column='co', max_length=32768) phone = CharField(db_column='telephoneNumber', max_length=32768) title = CharField(db_column='title', max_length=32768) bio = CharField(db_column='description', max_length=1024) email = CharField(db_column='mail', max_length=256) urls = ListField(db_column='labeledURI') startyear = IntegerField(db_column='domesdayStartYear', max_length=32768) tshirtsize = CharField(db_column='domesdayTShirtSize', max_length=32768) password = CharField(db_column='userPassword', max_length=128) photo = ImageField(db_column='jpegPhoto') def get_tags(self): tags = Tag.objects.filter(members__contains=self.dn) return [t.name for t in tags] def set_tags(self, tags): # Create Tag objects for each tag in the list (new ones # if necessary) and make sure the user is a member of all of them. for tag in tags: try: t = Tag.objects.get(name=tag) except Tag.DoesNotExist: t = Tag(name=tag) if not self.dn in t.members: t.members.append(self.dn) t.save() # Remove user from tags which were not specified current_tags = Tag.objects.filter(members__contains=self.dn) for ct in current_tags: if not ct.name in tags: if len(ct.members) == 1: # They are the only person left with this tag ct.delete() else: ct.members.remove(self.dn) ct.save() tags = property(get_tags, set_tags) def get_accounts(self): accts = Account.scoped("uid=%s,%s" % (self.uid, Account.base_dn)) return accts.objects.all().values() def set_accounts(self, accounts): # Create Account objects for each account in the list (new ones # if necessary). MyAccount = Account.scoped("uid=%s,%s" % (self.uid, Account.base_dn)) current_accts = MyAccount.objects.all() """ XXX FilterExceptions... for a in accounts: try: ca = MyAccount.objects.get(domain=a['domain']) ca.userid = a['userid'] except MyAccount.DoesNotExist: ca = MyAccount(domain=a['domain'], userid=a['userid']) ca.save() """ # Remove user from accounts which were not specified account_domains = [a['domain'] for a in accounts] for ca in current_accts: if not ca.domain in account_domains: ca.delete() accounts = property(get_accounts, set_accounts) def get_userid(self, domain): accts = Account.scoped("uid=%s,%s" % (self.uid, Account.base_dn)) account = accts.objects.filter(domain=domain) if account: return account[0].userid else: return None # This returns an object whose layout matches the PortableContacts schema # http://portablecontacts.net/draft-spec.html (retrieved 2011-04-19) # XXX Need to check doc more carefully and make sure it actually does in # every respect. def json_struct(self): json_struct = { "displayName": self.name, "name": { "formatted": self.name, "familyName": self.familyName, }, "nickname": self.nickname or "", "id": self.uid } if self.tags: json_struct["tags"] = [tag for tag in self.tags] if self.email: json_struct["emails"] = [{ "value": self.email, "primary": "true" }] if self.urls: json_struct["urls"] = [{ "value": u, "type": "other" } for u in self.urls] if self.phone: json_struct["phoneNumbers"] = [{ "value": self.phone }] if self.photo: json_struct["photos"] = [{ # XXX not an absolute URL, only site-relative "value": url('domesday.views.photo', pk=self.uid), "type": "thumbnail" }] if self.address or self.locality or self.country: json_struct["addresses"] = [{ "streetAddress": self.address or "", "locality": self.locality or "", "country": self.country or "", "formatted": self.address + "\n" + self.country }] if self.accounts: json_struct["accounts"] = [{ "domain": a['domain'], "userid": a['userid'] } for a in self.accounts] return json_struct def __str__(self): return self.name def __unicode__(self): return self.name def save(self, using=None): # Make sure all required fields are populated (sn and cn) if not self.familyName: self.familyName = " " if not self.cn: self.cn = self.familyName super(Person, self).save(using)
class Netgroup(BaseLdapModel): base_dn = 'ou=netgroups,' + settings.LDAP_BASE_DN object_classes = force_bytestrings(['nisNetgroup', ]) name = CharField(db_column=force_text('cn'), primary_key=True) triple = ListField(db_column=force_text('nisNetgroupTriple')) member = ListField(db_column=force_text('memberNisNetgroup'))
class Person(ldapdb.models.Model): """ A Domesday person. """ base_dn = "ou=people,dc=mozillians,dc=org" object_classes = ['inetOrgPerson', 'domesdayPerson'] uid = IntegerField(db_column='uid', max_length=256, primary_key=True) cn = CharField(db_column='cn', max_length=32768) givenName = CharField(db_column='givenName', max_length=32768) familyName = CharField(db_column='sn', max_length=32768) name = CharField(db_column='displayName', max_length=32768) nickname = CharField(db_column='domesdayNickName', max_length=32768) title = CharField(db_column='title', max_length=32768) address = CharField(db_column='postalAddress', max_length=1024) locality = CharField(db_column='l', max_length=32768) bio = CharField(db_column='description', max_length=1024) email = CharField(db_column='mail', max_length=256) # XXX Do we need a PasswordField type? password = CharField(db_column='userPassword', max_length=128) photo = ImageField(db_column='jpegPhoto') def get_tags(self): return Tag.objects.filter(members__contains=self.dn) def set_tags(self): pass tags = property(get_tags, set_tags) # Blog and website are stored as labeledURI fields, with the labels 'blog' # and 'website'. This means we need some mapping. labeledURIs = ListField(db_column='labeledURI') def get_uri(self, tag): test = re.compile("^(.*) " + tag + "$") results = filter(test.search, self.labeledURIs) if len(results): return test.match(results[0]).group(1) else: return "" def set_uri(self, tag, value): # Extract the old version, if present test = re.compile("^(.*) " + tag + "$") results = filter(lambda u: not test.search(u), self.labeledURIs) # Add the new one results.append(value + " " + tag) self.labeledURIs = results return self.get_uri(tag) def get_website(self): return self.get_uri("website") def set_website(self, website): return self.set_uri("website", website) website = property(get_website, set_website) def get_blog(self): return self.get_uri("blog") def set_blog(self, blog): return self.set_uri("blog", blog) blog = property(get_blog, set_blog) country = CharField(db_column='co', max_length=32768) phone = CharField(db_column='telephoneNumber', max_length=32768) tshirtsize = CharField(db_column='domesdayTShirtSize', max_length=32768) startyear = IntegerField(db_column='domesdayStartYear', max_length=32768) # XXX accounts/system IDs # This returns an object whose layout matches the PortableContacts schema # http://portablecontacts.net/draft-spec.html (retrieved 2011-04-19) # XXX Need to check doc more carefully and make sure it actually does in # every respect. def json_struct(self): json_struct = { "displayName": self.name, "name": { "formatted": self.name, "familyName": self.familyName, "givenName": self.givenName or "" }, "nickname": self.nickname or "", "id": self.uid } if self.tags: json_struct["tags"] = [tag.name for tag in self.tags] if self.email: json_struct["emails"] = [{"value": self.email, "primary": "true"}] if self.blog or self.website: json_struct["urls"] = [] if self.blog: json_struct["urls"].append({ "value": self.blog, "type": "blog" }) if self.website: json_struct["urls"].append({ "value": self.website, "type": "home" }) if self.phone: json_struct["phoneNumbers"] = [{"value": self.phone}] if self.photo: json_struct["photos"] = [{ # XXX not an absolute URL, only site-relative "value": url('domesday.views.photo', pk=self.uid), "type": "thumbnail" }] if self.address or self.locality or self.country: json_struct["addresses"] = [{ "streetAddress": self.address or "", "locality": self.locality or "", "country": self.country or "", "formatted": self.address + "\n" + self.country }] # "accounts": [ # {% for a in self.accounts %} # {% if not forlooself.first %}, {% endif %} # { # "domain": a.domain, # "userid": a.user # } # {% endfor %} #], return json_struct def __str__(self): return self.name def __unicode__(self): return self.name