Hello,
I have recently implemented the LDAPMembership adapter. It provides some good functionality in creating the list membership. However, the concept is there to provide access to one or more lists of email addresses (list membership is essentially a list of email addresses). I would like to use the LDAP functionality in other areas which require or use a list of email addresses (e.g. accept_these_nonmembers, hold_these_nonmembers, etc).
I have looked at the F.A.Q. on custom handlers and read the MailList.py file (under __init__) to see the 'extend.py' file being loaded.
Can someone better explain how loading the 'extend.py' file incorporates the files code and how the 'def extend' function is called? If I can understand how it works, perhaps, a solution to adding multiple LDAP search queries can be added to the extend.py file and used in other places in Mailman.
Thanks, Chris
P.S. When explaining, please realize I am moving from knowing absolutely nothing about Python to knowing next to nothing. :):)
C Nulk wrote:
I have recently implemented the LDAPMembership adapter. It provides some good functionality in creating the list membership. However, the concept is there to provide access to one or more lists of email addresses (list membership is essentially a list of email addresses). I would like to use the LDAP functionality in other areas which require or use a list of email addresses (e.g. accept_these_nonmembers, hold_these_nonmembers, etc).
I have looked at the F.A.Q. on custom handlers and read the MailList.py file (under __init__) to see the 'extend.py' file being loaded.
Can someone better explain how loading the 'extend.py' file incorporates the files code and how the 'def extend' function is called? If I can understand how it works, perhaps, a solution to adding multiple LDAP search queries can be added to the extend.py file and used in other places in Mailman.
Chris,
The extend.py mechanism as you use it basically just replaces the default mamber adaptor OLDStyleMembertships.py with LDAPMemberships.py for any list that has the extend.py file in it's lists/LISTNAME/ directory. In addition, it defines a few attributes which may or may not be list-specific which allow LDAPMemberships.py to get to the appropriate LDAP database.
If you've read the __init__ method in MailList.py, you've seen everything there is to see about extend.py. It gets called there and there only when the list is instantiated and sets the lists ._memberadaptor attribute to LDAPMemberships.
From then on, whenever a member adaptor method is called for that list, the method that is called is the one defined in LDAPMemberships.py.
So, for example, if your Mailman version is 2.1.10 or later so that it supports the @LISTNAME entry in *_these_nonmembers, and you put say @list2 in accept_these_nonmembers of list1, list1's processing of a non-member post will call list2's isMember() method to see if the poster is a member of list2, and if list2 already uses LDAPMemberships, that's it - it's isMember() method will use its LDAP database.
See the matches_p function in Mailman/Handlers/Moderate.py for more detail.
I hope this helps. If you still have questions, keep asking.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Thank you for replying Mark.
Mark Sapiro wrote:
C Nulk wrote:
I have recently implemented the LDAPMembership adapter. It provides some good functionality in creating the list membership. However, the concept is there to provide access to one or more lists of email addresses (list membership is essentially a list of email addresses). I would like to use the LDAP functionality in other areas which require or use a list of email addresses (e.g. accept_these_nonmembers, hold_these_nonmembers, etc).
I have looked at the F.A.Q. on custom handlers and read the MailList.py file (under __init__) to see the 'extend.py' file being loaded.
Can someone better explain how loading the 'extend.py' file incorporates the files code and how the 'def extend' function is called? If I can understand how it works, perhaps, a solution to adding multiple LDAP search queries can be added to the extend.py file and used in other places in Mailman.
Chris,
The extend.py mechanism as you use it basically just replaces the default mamber adaptor OLDStyleMembertships.py with LDAPMemberships.py for any list that has the extend.py file in it's lists/LISTNAME/ directory. In addition, it defines a few attributes which may or may not be list-specific which allow LDAPMemberships.py to get to the appropriate LDAP database.
If you've read the __init__ method in MailList.py, you've seen everything there is to see about extend.py. It gets called there and there only when the list is instantiated and sets the lists ._memberadaptor attribute to LDAPMemberships.
While I waited, I did do some reading/researching on __init__ which lead me to reading about __getattr__ and getattr. If I understand correctly, the LDAPMemberships uses them to get the isMember() and getMembers() methods among others.
From then on, whenever a member adaptor method is called for that list, the method that is called is the one defined in LDAPMemberships.py.
So, for example, if your Mailman version is 2.1.10 or later so that it supports the @LISTNAME entry in *_these_nonmembers, and you put say @list2 in accept_these_nonmembers of list1, list1's processing of a non-member post will call list2's isMember() method to see if the poster is a member of list2, and if list2 already uses LDAPMemberships, that's it - it's isMember() method will use its LDAP database.
Unfortunately, I am stuck at v2.1.9 for now.
See the matches_p function in Mailman/Handlers/Moderate.py for more detail.
I did look at Mailman/Handlers/Moderate.py, specifically the matches_p function. What I envisioned doing was to modify the matches_p function to single out "ldap" entries similar to the regex entries. Then for each "ldap" entry, call an LDAP2Dict function (to be written) which returns a dictionary of email addresses, then check if the sender was in the returned dictionary.
The changes made to LDAPMemberships.py would help since you explained to me that one of your changes was to make members a dictionary. The getMembers() method would essentially return that dictionary.
The key would be the changes to extend.py so everything works.
I hope this helps. If you still have questions, keep asking.
It has helped. I have made some changes to Mailman/Handlers/Moderate.py and Utils.py (to add the LDAP2Dict function). Let me know if you would like to see what I came up with and I can send the diffs and explaination to you off-list. You may have a better way to implement what I am doing. Well, actually, you probably do have a better way. :)
Thanks, Chris
C Nulk wrote:
While I waited, I did do some reading/researching on __init__ which lead me to reading about __getattr__ and getattr. If I understand correctly, the LDAPMemberships uses them to get the isMember() and getMembers() methods among others.
Not exactly. Since the MemberAdaptor is replaceable, it can't simply be a super class of the MailList class. Thus, it's methods are not in the name space of the MailList object so we need an __getattr__ method to access them from whatever class is assigned as the list's _memberadaptor. So when you reference a method such as mlist.isMember() that is not directly in the name space of the mlist instance so mlist.__getattr__('isMember') is called (behind the scenes) and it finds mlist._memberadaptor.isMember() and returns that.
This is true whether _memberadaptor is the default OldStyleMemberships class or the LDAPMemberships class or something else. The only thing that is specific to LDAPMemberships is the fact that the list's extend.py module assigned LDAPMemberships to _memberadaptor.
From then on, whenever a member adaptor method is called for that list, the method that is called is the one defined in LDAPMemberships.py.
So, for example, if your Mailman version is 2.1.10 or later so that it supports the @LISTNAME entry in *_these_nonmembers, and you put say @list2 in accept_these_nonmembers of list1, list1's processing of a non-member post will call list2's isMember() method to see if the poster is a member of list2, and if list2 already uses LDAPMemberships, that's it - it's isMember() method will use its LDAP database.
Unfortunately, I am stuck at v2.1.9 for now.
See the matches_p function in Mailman/Handlers/Moderate.py for more detail.
I did look at Mailman/Handlers/Moderate.py, specifically the matches_p function. What I envisioned doing was to modify the matches_p function to single out "ldap" entries similar to the regex entries. Then for each "ldap" entry, call an LDAP2Dict function (to be written) which returns a dictionary of email addresses, then check if the sender was in the returned dictionary.
That would work, but if this dictionary could be equated to the membership of some list, it seems to me that it would be easier to just backport the @listname feature to 2.1.9. You can find the original patch at <http://sourceforge.net/tracker/?func=detail&aid=1220144&group_id=103&atid=300103>. The 2.1.10 implementation is a bit more elaborate, but the SourceForge patch should be sufficient for your purpose.
Note that there is nothing magic about the dictionary in
plainaddrs = [addr for addr in nonmembers if not
addr.startswith('^')]
addrdict = Utils.List2Dict(plainaddrs, foldcase=1)
if addrdict.has_key(sender):
return 1
This could just as easily have been spelled
plainaddrs = [addr.lower() for addr in nonmembers if not
addr.startswith('^')]
if sender in plainaddrs:
return 1
The changes made to LDAPMemberships.py would help since you explained to me that one of your changes was to make members a dictionary. The getMembers() method would essentially return that dictionary.
No. getMembers() MUST return a list or everything breaks.
The key would be the changes to extend.py so everything works.
If you are accessing some LDAP directly (not via the @list construct) in the matches_p function, extend.py has nothing to do with it.
I hope this helps. If you still have questions, keep asking.
It has helped. I have made some changes to Mailman/Handlers/Moderate.py and Utils.py (to add the LDAP2Dict function). Let me know if you would like to see what I came up with and I can send the diffs and explaination to you off-list. You may have a better way to implement what I am doing. Well, actually, you probably do have a better way. :)
See my remarks above.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Mark Sapiro wrote:
C Nulk wrote:
While I waited, I did do some reading/researching on __init__ which lead me to reading about __getattr__ and getattr. If I understand correctly, the LDAPMemberships uses them to get the isMember() and getMembers() methods among others.
Not exactly. Since the MemberAdaptor is replaceable, it can't simply be a super class of the MailList class. Thus, it's methods are not in the name space of the MailList object so we need an __getattr__ method to access them from whatever class is assigned as the list's _memberadaptor. So when you reference a method such as mlist.isMember() that is not directly in the name space of the mlist instance so mlist.__getattr__('isMember') is called (behind the scenes) and it finds mlist._memberadaptor.isMember() and returns that.
Sorry about that. Your explanation is what I understood was the correct action(s) for the interaction between MailList and the MemberAdaptor. I just way to short in my explanation.
This is true whether _memberadaptor is the default OldStyleMemberships class or the LDAPMemberships class or something else. The only thing that is specific to LDAPMemberships is the fact that the list's extend.py module assigned LDAPMemberships to _memberadaptor.
From then on, whenever a member adaptor method is called for that list, the method that is called is the one defined in LDAPMemberships.py.
So, for example, if your Mailman version is 2.1.10 or later so that it supports the @LISTNAME entry in *_these_nonmembers, and you put say @list2 in accept_these_nonmembers of list1, list1's processing of a non-member post will call list2's isMember() method to see if the poster is a member of list2, and if list2 already uses LDAPMemberships, that's it - it's isMember() method will use its LDAP database. Unfortunately, I am stuck at v2.1.9 for now.
See the matches_p function in Mailman/Handlers/Moderate.py for more detail. I did look at Mailman/Handlers/Moderate.py, specifically the matches_p function. What I envisioned doing was to modify the matches_p function to single out "ldap" entries similar to the regex entries. Then for each "ldap" entry, call an LDAP2Dict function (to be written) which returns a dictionary of email addresses, then check if the sender was in the returned dictionary.
That would work, but if this dictionary could be equated to the membership of some list, it seems to me that it would be easier to just backport the @listname feature to 2.1.9. You can find the original patch at <http://sourceforge.net/tracker/?func=detail&aid=1220144&group_id=103&atid=300103>. The 2.1.10 implementation is a bit more elaborate, but the SourceForge patch should be sufficient for your purpose.
Note that there is nothing magic about the dictionary in
plainaddrs = [addr for addr in nonmembers if not addr.startswith('^')] addrdict = Utils.List2Dict(plainaddrs, foldcase=1) if addrdict.has_key(sender): return 1
This could just as easily have been spelled
plainaddrs = [addr.lower() for addr in nonmembers if not addr.startswith('^')] if sender in plainaddrs: return 1
I will have to take a closer look at the patch. And, I probably will apply it. From the quick glance on sourceforge, it looks like it should work for v2.1.9. All I should have to do is adjust the diff lines to point to the actual locations.
Being able to use another list as a source is great. I would still like to try to have everything defined/set within the list itself without cross-referencing other "management" lists. For us, it would be easier to manage.
The changes made to LDAPMemberships.py would help since you explained to me that one of your changes was to make members a dictionary. The getMembers() method would essentially return that dictionary.
No. getMembers() MUST return a list or everything breaks.
Okay. My mistake. Still trying to figure out Python and how things work. Since getMembers() returns a list, I suppose I could use the List2Dict() function to convert the list to a dictionary to be returned by my LDAP2Dict() function.
The key would be the changes to extend.py so everything works.
If you are accessing some LDAP directly (not via the @list construct) in the matches_p function, extend.py has nothing to do with it.
You will have to correct me if I am really off-base here on my understanding.
The extend.py module defines the extend() function which appears to set ldap (as an object of the LDAPMemberships class) ldap = LDAPMemberships(list) along with additional definitions, like ldap.ldapsearch = "(uid=somebody)" ldap.ldapserver = ldap.example.net and to tie it to the list, set the _memberadaptor to the object by list._memberadaptor = ldap
So when the list membership or some other method is accessed and not in the list namespace, your explanation above applies.
My idea of changing extend.py was to add additional objects of the LDAPMemberships class. Say an ldap2 and ldap3 like ldap2 = LDAPMemberships(list) ldap2.ldapsearch = "(uid=person1)" ldap2.ldapserver = ldap2.example.net list.<ldap2_identifier> = ldap2 ldap3 = LDAPMemberships(list) ldap3.ldapsearch = "(role=list-poster)" # as an example ldap3.ldapserver = ldap3.example.net list.<ldap3_identifier> = ldap3
both <ldap2_identifier> and <ldap3_identifier> are similar but not the same as the _memberadapter. The difference is <ldap2_identifier> and <ldap3_identifier> are specified in the accept_these_nonmembers (and the others) lists as LDAP=<ldap2_identifier> and likewise for any other "LDAP=" identifier.
The matches_p function (a parameter change would be needed, explained later) can separate out the "LDAP=" items and pass to the LDAP2Dict() function the list and ldap identifier.
The LDAP2Dict() function would use getattr(list, ldap-identifier) to locate the appropriate object of LDAPMemberships class.
So, for ldap2_identifier passed to LDAP2Dict(), getattr(list, ldap2_identifier) would return list.ldap2_identifier
Since I know that list.ldap2_identifier is an object with the getMembers() method, I should be able to get the "members" of the ldap2 search. And given that getMembers() returns a list, I can convert to a dictionary or possibly use List2Dict() to return the dictionary.
I do know that the list is not passed to the matches_p() function. For this to work, it would be added to the parameter list so the list can be passed to the LDAP2Dict() function.
I hope this helps. If you still have questions, keep asking.
It has helped. I have made some changes to Mailman/Handlers/Moderate.py and Utils.py (to add the LDAP2Dict function). Let me know if you would like to see what I came up with and I can send the diffs and explaination to you off-list. You may have a better way to implement what I am doing. Well, actually, you probably do have a better way. :)
See my remarks above.
I hope my explanations help you figure out what I am trying to do. The diffs may help you understand what I am trying to do.
I appreciate the help.
Thank you, Chris
C Nulk wrote:
I will have to take a closer look at the patch. And, I probably will apply it. From the quick glance on sourceforge, it looks like it should work for v2.1.9. All I should have to do is adjust the diff lines to point to the actual locations.
That's correct.
Being able to use another list as a source is great. I would still like to try to have everything defined/set within the list itself without cross-referencing other "management" lists. For us, it would be easier to manage.
That's your decision, but I think it complicates things. See below.
You will have to correct me if I am really off-base here on my understanding.
The extend.py module defines the extend() function which appears to set ldap (as an object of the LDAPMemberships class) ldap = LDAPMemberships(list) along with additional definitions, like ldap.ldapsearch = "(uid=somebody)" ldap.ldapserver = ldap.example.net and to tie it to the list, set the _memberadaptor to the object by list._memberadaptor = ldap
Yes.
So when the list membership or some other method is accessed and not in the list namespace, your explanation above applies.
My idea of changing extend.py was to add additional objects of the LDAPMemberships class. Say an ldap2 and ldap3 like ldap2 = LDAPMemberships(list) ldap2.ldapsearch = "(uid=person1)" ldap2.ldapserver = ldap2.example.net list.<ldap2_identifier> = ldap2 ldap3 = LDAPMemberships(list) ldap3.ldapsearch = "(role=list-poster)" # as an example ldap3.ldapserver = ldap3.example.net list.<ldap3_identifier> = ldap3
both <ldap2_identifier> and <ldap3_identifier> are similar but not the same as the _memberadapter. The difference is <ldap2_identifier> and <ldap3_identifier> are specified in the accept_these_nonmembers (and the others) lists as LDAP=<ldap2_identifier> and likewise for any other "LDAP=" identifier.
Consider the following instead.
Create a list named say posters with it's own extend.py with settings like ldap = LDAPMemberships(list) ldap.ldapsearch = "(role=list-poster)" # as an example ldap.ldapserver = ldap3.example.net list._memberadaptor = ldap etc.
Then all you need do is install the patch and put @posters in the original list's accept_these_nonmembers. You would also want to set the 'posters' list with attributes like
archive = No advertised = No default_member_moderation = Yes member_moderation_action = Discard generic_nonmember_action = Discard
so people wouldn't be aware of it and posts would not be accepted.
That way, the different LDAP functions would be defined for different "pseudo lists" and you wouldn't need any Mailman modifications other than installing a feature that's already implemented in current versions.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Mark Sapiro wrote:
Consider the following instead.
Create a list named say posters with it's own extend.py with settings like ldap = LDAPMemberships(list) ldap.ldapsearch = "(role=list-poster)" # as an example ldap.ldapserver = ldap3.example.net list._memberadaptor = ldap etc.
Then all you need do is install the patch and put @posters in the original list's accept_these_nonmembers. You would also want to set the 'posters' list with attributes like
archive = No advertised = No default_member_moderation = Yes member_moderation_action = Discard generic_nonmember_action = Discard
so people wouldn't be aware of it and posts would not be accepted.
That way, the different LDAP functions would be defined for different "pseudo lists" and you wouldn't need any Mailman modifications other than installing a feature that's already implemented in current versions.
Okay, okay, you've beaten me down. :):):) I do see your point. It is an additional management issue I wanted to avoid with the unadvertised lists.
Will this @list method also work for the other parameters/options that have a list of email addresses (like owner, moderator, ban_list, ...) or just the *_these_nonmembers options?
It probably sounds silly to do but if those options also take the @list method, I can set up several of my lists so all the options (with email address lists) are based out of ldap and have our system for creating accounts out of our HR system build the ldap entries, resulting minimal list management (for me at least :):)) The ban_list would not be an ldap list but in theory it could.
If not, I guess I will have to live with it. :)
Thanks, Chris
C Nulk wrote:
Okay, okay, you've beaten me down. :):):) I do see your point. It is an additional management issue I wanted to avoid with the unadvertised lists.
Will this @list method also work for the other parameters/options that have a list of email addresses (like owner, moderator, ban_list, ...) or just the *_these_nonmembers options?
It only works for *_these_nonmembers. It could be implemented for owner/moderator/etc, but these are more difficult as owner and moderator are referred to in more than one place.
Note that Mailman 3 will support a true back-end database for list membership and other roles. At that time, this will all become much easier.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Mark Sapiro wrote:
C Nulk wrote:
Will this @list method also work for the other parameters/options that have a list of email addresses (like owner, moderator, ban_list, ...) or just the *_these_nonmembers options?
It only works for *_these_nonmembers. It could be implemented for owner/moderator/etc, but these are more difficult as owner and moderator are referred to in more than one place.
Note that Mailman 3 will support a true back-end database for list membership and other roles. At that time, this will all become much easier.
I figured as much. And thank you for answering my next question about Mailman 3. Is there documentation somewhere I can read how to configure MM3 for using LDAP or any other back-end database?
Now back to the patch.
Thanks again, Chris
On Apr 14, 2009, at 5:28 PM, C Nulk wrote:
I figured as much. And thank you for answering my next question about Mailman 3. Is there documentation somewhere I can read how to
configure MM3 for using LDAP or any other back-end database?
Yes and no. There are lots of doctests in the MM3 code, which
primarily serve as documentation. Navigating around to find the
information you want may take some time as there's no overview. There
are currently no doctests describing how to use different backends,
but the basic idea is that MM3 is strongly component based, using Zope
style interfaces. If you can provide different implementations of the
backends for core objects (mostly in the mailman/database package),
then the rest of Mailman will just work.
Integrating different RDBMS should be pretty trivial. If Storm
supports it, then it's just changing a URL in a config file. For an
LDAP backend, it will take some additional implementation work to
write different implementations of IMailingList and such that don't do
SQL queries to gather the necessary information.
I'd be happy to help anybody who's interesting in building out an LDAP
backend.
-Barry
Hello Barry,
Thank you for responding. A quick question, will MM3 also support the @list funtionality, both for the 4 *_these_nonmembers options and the owner, moderator, and the ban_list options?
Barry Warsaw wrote:
On Apr 14, 2009, at 5:28 PM, C Nulk wrote:
I figured as much. And thank you for answering my next question about Mailman 3. Is there documentation somewhere I can read how to configure MM3 for using LDAP or any other back-end database?
Yes and no. There are lots of doctests in the MM3 code, which primarily serve as documentation. Navigating around to find the information you want may take some time as there's no overview. There are currently no doctests describing how to use different backends, but the basic idea is that MM3 is strongly component based, using Zope style interfaces. If you can provide different implementations of the backends for core objects (mostly in the mailman/database package), then the rest of Mailman will just work.
While I have heard about Zope, I am not familiar with it.
Integrating different RDBMS should be pretty trivial. If Storm supports it, then it's just changing a URL in a config file. For an LDAP backend, it will take some additional implementation work to write different implementations of IMailingList and such that don't do SQL queries to gather the necessary information.
I am also not familiar with Storm. I am guessing it is the Storm from http://storm.canonical.com. I did take a quick look at it but I suffer from several handicaps - main one being I know extremely little Python. Just ask Mark Sapiro about that :):). I also looked to see if there was an URL type interface for LDAP. There is however it would be primary be an anonymous bind to a LDAP service. Most if not all places will not allow anonymous binds which can update/change their LDAP information. I just don't know enough about Storm to say whether or not the DN bind can be worked in.
The current LDAPMembership.py get the LDAP data. It might be possible to use the ideas there to implement LDAP in Storm.
I'd be happy to help anybody who's interesting in building out an LDAP backend.
My poor knowledge of Python most likely leaves me out with respect to developing, however, I would be happy to be involved in contributing ideas towards the development.
One idea I did have is about keeping unsubscribe information. Since an LDAP query will always return every entry matching the query, someone that wishes to unsubscribe cannot because their entry is included in the query. If whatever mechanism is used to track a given list member's config settings (mod, ack, nomail, etc) also includes whether the person unsubscribed or not, then whenever the getMembers()/isMember() or equivalent functions are called, the query results minus the unsubscribed is checked/validated/etc. depending on the function.
Sorry if the above sounds like gibberish. Could really figure out how to say it better.
Thanks again,
Chris
C Nulk wrote:
Thank you for responding. A quick question, will MM3 also support the @list funtionality, both for the 4 *_these_nonmembers options and the owner, moderator, and the ban_list options?
I have a few remarks about this. The @listname feature was implemented in Mailman 2.1/2.2 after they diverged from 3.0 so it's not in 3.0 at this moment. It probably will be if it makes sense to do so.
However, for your situation, the whole notion of a member adaptor per se goes away in 3.0 and is replaced by the backend database interface, so this may not be that significant.
Regarding owner and moderator, my understanding (Barry will correct me) is that these roles are defined in the back-end rather than being list attributes per se so I think your question becomes moot at least for owner and moderator.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
On Apr 16, 2009, at 6:24 PM, Mark Sapiro wrote:
Regarding owner and moderator, my understanding (Barry will correct
me) is that these roles are defined in the back-end rather than being list attributes per se so I think your question becomes moot at least for owner and moderator.
Yes, 'member', 'moderator', and 'owner' are roles defined in the
member interface and used in the roster interfaces. They aren't tied
to users directly. In fact, they're actually tied to addresses (which
are tied to users) and a single address/user can play multiple roles.
-Barry
On Apr 16, 2009, at 5:05 PM, C Nulk wrote:
Hello Barry,
Thank you for responding. A quick question, will MM3 also support the @list funtionality, both for the 4 *_these_nonmembers options and the owner, moderator, and the ban_list options?
Well, not exactly. It should be possible to get the same
functionality, but it will have to be done differently. For example,
the *_these_nonmember attributes are gone.
Barry Warsaw wrote:
On Apr 14, 2009, at 5:28 PM, C Nulk wrote:
I figured as much. And thank you for answering my next question
about Mailman 3. Is there documentation somewhere I can read how to
configure MM3 for using LDAP or any other back-end database?Yes and no. There are lots of doctests in the MM3 code, which
primarily serve as documentation. Navigating around to find the information
you want may take some time as there's no overview. There are
currently no doctests describing how to use different backends, but the basic
idea is that MM3 is strongly component based, using Zope style interfaces.
If you can provide different implementations of the backends for core objects (mostly in the mailman/database package), then the rest of Mailman will just work.While I have heard about Zope, I am not familiar with it.
You don't really need to know much about Zope to understand
zope.interfaces. Really, just think of these as a formal way to
specify interfaces to components. The package originated in the Zope
world which is why it lives in the 'zope' namespace.
Integrating different RDBMS should be pretty trivial. If Storm
supports it, then it's just changing a URL in a config file. For an LDAP backend, it will take some additional implementation work to write different implementations of IMailingList and such that don't do SQL queries to gather the necessary information.I am also not familiar with Storm. I am guessing it is the Storm from http://storm.canonical.com.
Yep.
I did take a quick look at it but I suffer from several handicaps - main one being I know extremely little
Python. Just ask Mark Sapiro about that :):).
;)
I also looked to see if there was an URL type interface for LDAP. There is however it would be
primary be an anonymous bind to a LDAP service. Most if not all places will not allow anonymous binds which can update/change their LDAP
information. I just don't know enough about Storm to say whether or not the DN bind
can be worked in.The current LDAPMembership.py get the LDAP data. It might be possible to use the ideas there to implement LDAP in Storm.
I don't think LDAP is a good fit for Storm, which really wants to be
talking to a relational database via SQL. The bad news is that using
Storm is the easy way to hook MM3 up to a different backend. The good
news is that (hopefully) that's not necessary to use LDAP for your
user data. I think you would need to re-implement things like the
UserManager, but this is mostly uncharted waters.
I'd be happy to help anybody who's interesting in building out an
LDAP backend.My poor knowledge of Python most likely leaves me out with respect to developing, however, I would be happy to be involved in contributing ideas towards the development.
One idea I did have is about keeping unsubscribe information. Since
an LDAP query will always return every entry matching the query, someone that wishes to unsubscribe cannot because their entry is included in
the query. If whatever mechanism is used to track a given list member's config settings (mod, ack, nomail, etc) also includes whether the
person unsubscribed or not, then whenever the getMembers()/isMember() or equivalent functions are called, the query results minus the unsubscribed is checked/validated/etc. depending on the function.Sorry if the above sounds like gibberish. Could really figure out how to say it better.
I think I see what you're saying. You really want to split user data
across LDAP and say a relational database. While I think it could be
done (and probably /should/ be doable), it will take some clever model-
layer programming to make it work. I don't have a clear picture in my
mind about how to do that right now, but it's worth an interested
developer to take a look at it.
-Barry
Barry Warsaw wrote:
I also looked to see if there was an URL type interface for LDAP. There is however it would be primary be an anonymous bind to a LDAP service. Most if not all places will not allow anonymous binds which can update/change their LDAP information. I just don't know enough about Storm to say whether or not the DN bind can be worked in.
The current LDAPMembership.py get the LDAP data. It might be possible to use the ideas there to implement LDAP in Storm.
I don't think LDAP is a good fit for Storm, which really wants to be talking to a relational database via SQL. The bad news is that using Storm is the easy way to hook MM3 up to a different backend. The good news is that (hopefully) that's not necessary to use LDAP for your user data. I think you would need to re-implement things like the UserManager, but this is mostly uncharted waters.
As I walked to the train station last night, I came to the same conclusion. Since LDAP is not relational, Storm would need to make exceptions for LDAP. Definitely not a good fit.
I'd be happy to help anybody who's interesting in building out an LDAP backend.
My poor knowledge of Python most likely leaves me out with respect to developing, however, I would be happy to be involved in contributing ideas towards the development.
One idea I did have is about keeping unsubscribe information. Since an LDAP query will always return every entry matching the query, someone that wishes to unsubscribe cannot because their entry is included in the query. If whatever mechanism is used to track a given list member's config settings (mod, ack, nomail, etc) also includes whether the person unsubscribed or not, then whenever the getMembers()/isMember() or equivalent functions are called, the query results minus the unsubscribed is checked/validated/etc. depending on the function.
Sorry if the above sounds like gibberish. Could really figure out how to say it better.
I think I see what you're saying. You really want to split user data across LDAP and say a relational database. While I think it could be done (and probably /should/ be doable), it will take some clever model-layer programming to make it work. I don't have a clear picture in my mind about how to do that right now, but it's worth an interested developer to take a look at it.
-Barry
Well, not really splitting up the data between LDAP and a relational DB because you will end up with sync problems at some point in time. It was more of adding/modifing text attribute values in LDAP. I will explain it more fully next week when I start a new thread (I just saw your responses and I need to close up and head for the train).
Chris
participants (4)
-
Barry Warsaw
-
Barry Warsaw
-
C Nulk
-
Mark Sapiro